Sunday, August 10, 2014

AppleScript to JavaScript

No fate but what we make. - Sarah Connor (T2)

One of the things I love about OSX is that most applications are scriptable. They expose the ability to send AppleEvents and control various features of the application. In the older days, the way a menu interacted with the app was by sending AppleEvents, so using scripting, you could do anything that the menus could do. While the architecture is a little different today, developers know they need to make their apps scriptable to be real apps.

This means that I have a ton of scripts that do crazy stuff. Check Calendar to see if I'm in a meeting and then update my Adium IM status. Rip a movie from DVD, search The Movie DB, and then update the metatags. Check the temperature outside (Forecast.io) and inside (Nest) and send a notification to my phone (Growl) if my windows should be opened or closed. So slick.

While I love the fact that I can script all this, it's a sad that I have to use AppleScript to do it. The AppleScript language is one of those great ideas that just never quit became what it was meant to be. I talk a lot to people about the language - because I think it's an interesting case study of things gone bad.

OSX Yosemite is moving to replace AppleScript with JavaScript. Sweet. I know JavaScript! I tried to starting converting one of my simpler scripts (Set Adium status based on Calendar) and failed quickly. I don't know how to read Enums and there is NO documentation on this available yet. I've posted to StackExchange and Apple Dev Forums. I'll see if I get help

AppleScript:

tell application "Adium"
    if status type of global status is offline then
        log "offline"
    end if
end tell

JavaScript? (I can't make it work):

if(Application('Adium').globalStatus.statusType == ?????) {
    console.log("offline");
}
Application('Adium').StatusType("offline"); // error
Application('Adium').StatusType.offline;     // undefined
Application('Adium').StatusType.make({name:"offline"}); // error

Update: I solved it. Directly accessing the property gives you back the object reference such as AdiumRichText. If you put parenthesis at the end() then it calls the getter and coerces it into JavaScript objects:

if(Application('Adium').globalStatus().statusType() == "offline") {
    console.log("offline");
}

Anyway - this is COOL: