Building Script Applications

f you’re like me, you tend to mostly just write scripts, install them in the Scripts folder, and run them from the Script Menu. But there ARE times when it makes sense to save a script as an application rather than as a script. Here we’ll talk about just two examples where it makes sense (or is necessary) to create a script application.

Build Your Own Connection Checker
The other day my internet connection went down. It happens to all of us at one time or another. If you have your phone service through your cable line, like I do, a cable outage is not just an inconvenience - it’s crippling. So, being a scripter, I decided to toss together an Applescript application that would notify me when the connection was back up.

Also being a Mac user, just a dialog box wasn’t sufficient notification. Since the Mac has speech capabilities, I though, “Why not let the Mac tell me when the system’s back up?” That way, I can walk away from the machine until the service comes back.

Below is the complete script. As you can see, it’s fairly simple, but it does include an idle handler. Idle handlers don’t work in regular scripts - you must save your script as an application to get this functionality.

property myCmd : "ping -c 1 "
property myResult : ""
property idleDelay : 60
property cmdWait : 10

--Get a URL to test
display dialog "Enter address to ping:" default answer ""
set theUrl to the text returned of the result
set myCmd to myCmd & theUrl

--find out how long to wait before timing out
display dialog "How long should I wait? (in seconds)" default answer cmdWait
set cmdWait to the (text returned of the result) as integer

--how often should the script check back?
display dialog "How often should I check? (in seconds)" default answer idleDelay
set idleDelay to the (text returned of the result) as integer

--Format the URL so it can be spoken
set astid to AppleScript's text item delimiters
set AppleScript's text item delimiters to space
set theUrl to (words of theUrl as text)
say "Checking connection " & theUrl
set AppleScript's text item delimiters to astid

on idle
	say "Attempting ping."
		with timeout of cmdWait seconds
			set myResult to do shell script myCmd
		end timeout
	end try
	display dialog myResult
	if myResult contains "packet loss" then
		--we got a (non-empty) result
		if myResult contains "100%" then
			--only consider 100% loss a failure
			say "Can't connect to " & theUrl
			--Any other % is a valid connection
			say "Connection made."
			quit me
		end if
		--if we got an empty result, the command timed out.
		say "Command timeout."
	end if
	return idleDelay
end idle

An idle handler is called once when the script starts, and thereafter is called as frequently as you specify with the value returned. The returned “idleDelay” tells Applescript how long to wait before calling the idle handler again. By default Applescript comes back every 30 seconds unless you return a value other than that. I set the delay at 60 seconds, but you can change that to any positive number. Non-numeric values cause no change in the delay frequency.

In addition, the ping command can take some time to run if the network is congested or slow. So the script uses a with timeout block to cancel the command if no result is back in a given amount of time (10 seconds by default here).

Saving as an application is simple: Just select “application” in the save dialog’s “File Format” popup. If (as in this case) your application uses an idle handler, you need to select the “Stay Open” checkbox, too. Whether you want the application to show a startup screen is up to you, but I find them annoying and turn that checkbox off. If you want to protect your code (say, from other users who might mess with it), you can select the “Run Only” option. If you do this, make sure you have a copy that isn’t “Run Only!” If you don’t, you will not be able to make changes to the script application once you save it!

Build Your Own Program Launcher
One of the subjects that Mac users love to argue about is program launchers. The early Mac OS had a control panel called the Launcher that people either loved or hated, much like the current Dock. And while I don’t mind using the Dock, its space is rather limited and I have a large number of programs that I want available quickly rather than digging through the Applications folder.

Back in the pre-OS X days, Applescript supported the Favorites folder with an add to Favorites command that added aliases to a Favorites folder in your Apple Menu. If you check your Standard Additions OSAX today, however, you’ll see that it is deprecated. That means it’s no longer supported and will likely disappear from the dictionary in a future release. And the Apple Menu stopped being a program launcher when OS X was released. Some folks like Quicksilver or other launchers, and while I’m sure they’re great, if all you need is a launcher and a way to manage launcher items, there’s a way that Applescript can help.

Inside your Library folder there still exists a “Favorites” folder. It was originally put there to support Internet Explorer, I think, but when Apple started their own browser, they ignored the Favorites folder and dropped any support for it.

Which means it’s just sitting there doing nothing, so let’s use it! If you don’t mind using the Dock as part of your own Launcher, you’ll soon have a working program launcher. Drag the Favorites folder to the right side of your dock (where the trash can and minimized windows are kept). If you don’t have a Favorites folder, just create a new folder in Library and name it “Favorites.”

OK, now what? Well, if you right click the Favorites dock icon, you’ll see it gives you a standard context menu with options to remove, open at login, show in Finder, or open the folder. However, if you put aliases to your often-used items in the Favorites folder, it suddenly becomes a program launcher! If you have other folders in the Dock, you can give the Favorites folder a custom icon to differentiate it from the others. Mine has an Apple icon (I made my own Apple Menu, thank you!).

Of course, you don’t want to have to constantly open your Library/Favorites folder(s) to maintain the launcher aliases. So here’s a simple script that will do that for you (and you can add other functions, if you like):

set currentFolder to path to favorites folder
set folderText to ""
set theSelection to {}
set selText to {}
set menuList to {"Parent folder", "Create folder", "Alias selection", "Move selection", "Quit"}
set folderList to {}
set done to false

	--load the sort library (from the Nite Flite library, see below for link)
	set scriptPath to ((path to scripts folder from user domain) as text) & "Script Library:"
	set sortLib to load script ((scriptPath as text) & "sortLib.scpt") as alias
	tell application "Finder"
		--get the selection
		set theSelection to the selection
		if length of theSelection = 0 then
			set selText to "none"
			repeat with anItem in theSelection
				set end of selText to displayed name of anItem
			end repeat
			set selText to selText as text
		end if
		-- repeat until done
		repeat while not done
			--create text bits for display
			set folderText to displayed name of currentFolder
			set tempList to folders of currentFolder
			set folderList to {}
			--get folders
			repeat with anItem in tempList
				set end of folderList to "Open folder " & displayed name of anItem
			end repeat
			set tempList to alias files of currentFolder
			--find folder aliases
			repeat with anItem in tempList
				if kind of (the original item of anItem) is "folder" then set end of folderList to "Open folder " & displayed name of anItem
			end repeat
			--sort the list of folders and aliases to folders
			set folderList to sortLib's quicksort(folderList)
			set newMenu to menuList & folderList
			--show the menu and get a choice
			set theChoice to (choose from list newMenu with title "Manage Favorites" with prompt "Current folder: " & folderText & return & selText without multiple selections allowed) as text
			--do actions for each choice
			if theChoice is "quit" or theChoice is "false" then
				set done to true
			else if theChoice is "Parent folder" then
				set currentFolder to container of (currentFolder as alias)
			else if theChoice is "Create folder" then
				display dialog "Name for new folder?" default answer "newfolder"
				set newfolder to text returned of the result
				set currentFolder to make new folder at currentFolder with properties {name:newfolder}
			else if theChoice is "Alias selection" then
				repeat with anItem in theSelection
					make new alias file at currentFolder to anItem
				end repeat
			else if theChoice is "Move selection" then
				repeat with anItem in theSelection
					move anItem to currentFolder
				end repeat
			else if word 1 of theChoice is "Open" then
				set lastChar to count characters of theChoice
				set theTarget to text 13 thru lastChar of theChoice
				set currentFolder to (item theTarget of currentFolder)
			end if
		end repeat
	end tell
on error the error_message number the error_number
	display dialog "Error: " & the error_number & ". " & the error_message buttons {"OK"} default button 1
end try

Editor’s note: This script uses Kevin’s Nite Flite library to do the sorting. You can find it here.

Of course, you can put this in your Script Menu as a regular script, but doesn’t it make more sense to have it in the Favorites folder? If you save it as a regular script there, though, it will launch Script Editor when you try to run it! So here we have another example of a script that should be an application. Save the file as something like “Manage Favorites” in your Favorites folder. Select “application” in the save dialog, and make sure that you turn off “Stay Open,” since you don’t need it.

The application presents a menu that will let you create an alias of selected Finder items or move the selection to the current folder (shown in the top of the list dialog). So you only need to select items in the Finder and run the script. The script allows you to create new folders and move up and down in the folder hierarchy.

So now you’ve got your own launcher, that can be as personal as you! Add to the items, create subfolders, and add any other functions you want to. That’s the beauty of scripting - you can personalize your system to the way YOU like to work!

I hope you’ve got a better idea now as to when it’s appropriate to use an application rather than a vanilla script. Another good use, which we didn’t cover here, is drag and drop applications (sometimes called “droplets”). Craig Smith has a great article on droplets if you want to learn more.