JavaScript for Automation

Session 306 WWDC 2014

Automation in OS X has always been about power and choice. Scriptable applications, including Pages, Keynote, Numbers, and the Finder, can already be automated using a variety of languages, including AppleScript, Objective-C, Perl, Python, and Ruby. With OS X Yosemite, application scripting support has been added to another popular language, JavaScript. JavaScript for Automation (JXA) extends the standard JavaScript environment provided by the JavaScriptCore framework with support for querying and controlling all of the scriptable applications running in OS X. JXA scripts are supported at all layers of the system and can be invoked from the command-line, from the system-wide Script Menu, and can even be distributed as code-signed applications.


Welcome to Friday.

Thanks for being here.

My name is Sal Soghoian.

I am the Product Manager for Automation Technologies at Apple, Inc.

And this is Session 306, this is a big day.

We get to welcome JavaScript to the family of scripting languages on OS X.

[ Applause ]

We've been waiting a long time for this and I know our customers have, too, and we're really thrilled about it.

And before I get into the details of the language and how it works I'd like to take a moment to reflect on the state of automation, beginning with Mavericks.

Now, in Mavericks we introduced a host of new features, some very powerful things beginning with notification support in both the scripting language and in Automator as well.

So it became very easy to use notifications instead of posting dialogues in your automation routines.

We also introduced Code Signing ability in our Editor applications, both in Automator and in the Script Editor, which is great because then you could sign and deliver Automation solutions to your customers, friends and coworkers.

We also introduced a new construct in AppleScript called the "use" statement that acts like an importer to import functionality from applications and frameworks and scripting editions, and allow them to be used in your scripts.

And by doing this we also made it possible to have Script Libraries that we introduced.

And Script Libraries are scripts that you create yourself that contain your favorite sub-routines or handlers, and you can call and load these libraries from scripts anywhere in the operating system.

You can also take advantage of AppleScript Objective-C and any of the Cocoa calls that you want to use.

So they were very powerful, very useful they be introduced.

And then finally, we had a new feature that worked on English-only systems but we thought it was so interesting that we introduced it.

It was called Speakable Workflows, and it allowed you to take your Automator workflow and save it as a speakable item in the dictation architecture.

So you could say a command and it would run your workflow.

And so Mavericks was a very productive release for us, we were very excited about it, but we were also excited about what we've done in Yosemite and how it builds upon the groundwork we laid in Mavericks.

As part of this evolutionary process, we integrated Code Signing with workflow files.

So not only applets but now your workflow files can be Code-Signed as well.

And because of changes that we implemented in the AppleScript language for supporting optional parameters in sub-routines and handlers we were enabled to upgrade the scripting library support so that you can now have your favorite calls have optional parameters and use those as well.

Very good improvement there.

And listening to customer requests that have been for years and years, requesting some way to indicate a progress method for their Automation routines, we now have built-in script progress indicators.

So, by calling simple properties you can have your scripts display a progress indicator, a circle, or even as a progress bar in a floating window, and all of this is done for you automatically, all you have to do is set properties within your scripts.

So I think our customers are going to really enjoy that particular feature.

And we took the idea of Speakable Workflows and we've advanced it now because of the dictation architecture in Yosemite that works with all languages.

We now have a new template item in Automator for creating a Dictation Command.

So you create your workflow, you save it, it gets saved into the dictation architecture and when you're in the process of dictating or just sitting at the machine, you can say the name of your command and it will execute.

Very interesting, very powerful, I know you're going to have a lot of fun exploring that.

So that's just a quick overview of where we've been, but something that's been on our minds for a long time that we've happy and very pleased to have here today is JavaScript for Automation.

Now, those of you that are familiar with JavaScript from the web-based community, this is not the JavaScript for writing a DOM that uses CSS and HTML5 to create a web app.

We're talking about extending the JavaScript core language to integrate with the open scripting architecture.

And by doing this, you have now gained the ability to pull all those levers inside of the scriptable apps on your operating system to perform the kind of repetitive or interesting or complex tasks that you do every day.

And now this power is available to you through JavaScript.

Now many of you that write JavaScript professionally or as your focus, you're used to using editors like BBEdit, Sublime Text, WebStorm, TextMate, things like that.

Initially, as you adapt to JavaScript for Automation, you'll write your first scripts in the Script Editor application.

And I'm going to give you just a short overview of this application, its interface and preferences so that you'll understand what's happening as David presents JavaScript for you.

So let me take a look at the Script Editor application.

So when you open the Script Editor Application you get this very simple interface, this is a script window.

And it has a simple but very powerful design to it, beginning with the little slider that separates the two main panes of the window, the script pane where you enter the code for your script, and the bottom pane contains an event log.

So as the script is executing you'll see the events listed there with the results coming in from the events.

And this is a live log that happens as the script is executing.

At the top there are some simple controls for basically compiling the script to make sure your syntax is correct, and there's also a control for running or stopping your script.

Now, there at the bottom here is a language control.

So make sure if you're writing JavaScript that this popup menu is set for the JavaScript language.

And that's basically the interface, and the way that it works is you enter your script code into the top area, then you click the Run button and as it executes you can see that there's a progress indicator here on the right showing the progress of the script, and you can watch the event log go by.

Now this simple script that exported open Keynote documents to movies, you can see the results of it and how it was logged and everything indicated in the final result of the script at the bottom.

So this is the interface that you have when you're executing scripts, and as David shows you the examples, this is what you're going to see.

There's some other important preferences you should be aware of and let me just quickly show those to you.

So, in the Preferences menu from the Application menu, in the General Settings pane there is a Default Language popup.

If you're going to be using JavaScript as your primary language for scripting you want to make sure that you change this value to JavaScript.

Now this says JavaScript 1.0.

This is JavaScript for Automation 1.0.

It is not JavaScript 1.0.

We use the current JavaScript core language as the basis.

So don't be freaked out when you see 1.0 there.

Also, make sure that you check the Show Script menu in menu bar option, and what this will do is activate the system-wide Script Menu at the top right of your menu bar.

And from this Script Menu you can host your favorite scripts and you can make them available contextually within certain applications.

So if you write scripts for the Finder, they can only appear if the Finder's there.

If you write scripts for Pages, they'll only appear when Pages are there.

It's up to you, the Script Menu runs shell scripts, Apple scripts, applications, workflows, JavaScripts, any kind of scripting language supported by the operating system can run from the Script Menu.

So you'll be taking advantage of that.

In addition, if you want to set certain coloring for the code that you use, this formatting pane is where you'll do that.

You can choose fonts, font size and coloring to apply to fit comfortably with what you're used to.

Next, I'd like to look at dictionaries.

Now, in the operating system, every scriptable application carries internally within its bundle a complete dictionary of all the terms that it understands.

It will list all the classes and all the methods and the commands and the properties and elements that it is familiar with.

So this is where you will go to learn about how to control a particular application.

And what you do is you choose Open Dictionary from the File menu and in the forthcoming dialogue choose an application.

When you do that you'll see a script viewer window like this one for the Keynote dictionary, and this is what you see when you look at an application's scripting dictionary, and this is what you will do to navigate that dictionary.

At the top is a Language button, so this dictionary viewer functions for all the scripting languages we support, so it supports JavaScript, AppleScript or Objective-C, and you can change the mode for viewing the content right from this menu.

Now at the top part of this window, the top pane of this window, is the Model Viewer.

And this is where you see how the objects in the application scripting model are reflected.

On the left-hand side, typically a scripting dictionary is grouped into suites, and these suites are usually grouped by functionality, by what they do.

In this particular example you'll see that there's multiple suites.

There's suites for iWork.

Because Keynote is part of the iWork family of applications, the iWork Suites of common objects and common commands are included there.

And then Keynote has its own suite of things that are particular for the Keynote application.

And then once the suite is selected, you'll see in the next column the methods and the classes that belong to that particular suite.

So here we have commands like Export, where you would export a presentation.

And you see classes like document.

And then when you select a class, you'll see the elements that belong to that class in the right-hand column, and also the properties of that particular class.

And here you see the properties of a Keynote document.

Now for further information and detail about these, in the bottom half of the window is the dictionary viewer.

And the dictionary viewer contains the definitions for all of those particular elements.

So when you want to know about, well, how do I script the Finder, or how do I script Numbers, how do I script Keynote, how do I script Aperture?

You open a dictionary and this is where you learn and explore to find out how to control those applications.

So that's the scripting dictionary, and that's the Script Editor application.

So, let me get out of the way and bring up David Steinberg, who's the newest member of our team, to show you JavaScript for Automation.

Enjoy this [applause].

Thank you, Sal.

Hello, everyone.

Thank you for being here.

It's a great honor.

I'm really excited to be showing you this awesome new feature of OS X Yosemite, JavaScript for Automation.

So today's talk will cover what JavaScript for Automation is and how it works, how you can use JavaScript for Automation from basic to more advanced techniques, and finally we'll talk about where you can use JavaScript for Automation.

So to talk about what JavaScript for Automation is, let's take a look at the underlying pieces.

Automation allows you to accomplish tasks on your Mac automatically, from simple tasks, such as changing the name of a hundred files all at once, to more complex tasks, such as sending personalized directions to guests before a party you're having.

I'd like to demonstrate the power of Automation to you now.

So I work for Acme Widgets, we're a company that makes widgets, as you might expect.

We have three main clients, Japan, USA, and then across Europe, and here I have a chart detailing some of our widgets' prices and the regions they go to, and the particular currency, and so on.

And now I have four upcoming presentations.

First, I have to give a presentation to the president of the company about all of the regions that we work with, all of their individual prices, currencies, and so on, and then I have to give presentations to each of those regions only detailing the particular information that pertains to that region.

So, now I'm thinking, okay, I have four Keynotes I have to make.

Well, let's start with the first.

I have all my data here, it's formatted as I want it, I have some images that I can use related to this data.

How about I write a script that does this for me?

Well, I've done just that.

So here I have a script, don't worry about understanding all of it at the moment, but it's a JavaScript for Automation script that uses this Numbers document and produces a full slide deck for me in Keynote.

So if I run this here, we see our slides are being created for us with the information that we got from that data, and now we have an entire slide deck ready for my president to see, detailing all of our widgets, their prices per region, currency, and so on.

This is perfect.

Okay, so I've accomplished one, completely automatically.

I have three more to do, and each of those are going to be pretty much the exact same.

Same number of slides, same images, same information, changed per region with particular currency and so on.

And in fact, all of that information is already in this presentation I have here, I just need to slim it down for each version.

So I wrote myself a helper script, I'm going to use it multiple times, so I put it in my script menu.

And what this does is it lets me say, where am I presenting today?

Well, today I'm going to be presenting in Japan.

So I just slim down my Keynote to the few slides that are important, put it in presentation mode and I'm able to go.

Hello everyone, thank you for being here.

Let's talk about prices.

It's been a real pleasure, have a good day.

Now [laughter], right?

Now, I'm going to be giving a presentation for the USA.

Okay, I don't want to make another slide deck all together, I'm going to use my nice little helper here, USA.

Hello everybody, thank you for being here.

Let's talk some dollars.

It's been a real pleasure, have a nice day.


That entire automatable process was automated for me with just a couple little scripts that I wrote.

That made my life easier, got my work done faster.

And that is the power of Automation.

[ Applause ]

Those demos were made possible by scripting applications, and applications that are built using Cocoa automatically have a certain level of scriptability, such as being able to be told to open, or to print.

And a wide variety of applications have fully embraced scriptability, detailing the Object Model of the application and offering rich suites of functionality beyond the basics.

Apple events are the underlying communication mechanism behind application scripting.

They provide access to the scriptable pieces and parts of an application that are defined in an application's scripting dictionary, as Sal showed, detailing what objects can be interacted with and how.

So when you script an application in whatever language you may, its scripting dictionary is read and then Apple events are used to communicate with the application.

So let's take a look at an example of an Object Model.

Here we have Mail, which has an application object with an inbox property, with a messages element array, with each element individually accessible.

So for example, we could pinpoint the second message of the inbox of the application mail, as an object specifier, or a reference to that particular object in that particular application.

This is great, we've looked really closely at the things behind Automation and application scripting.

Now let's talk about JavaScript and how the power of Automation was brought to it.

JavaScript is a scripting language with C-like syntax and objects with prototype-based inheritance.

It's most well known in the browser being the scripting language of HTML5.

But it's also become quite popular as a server-side scripting language, evidenced by Node.js.

JavaScript on OS X is powered by JavaScriptCore, the engine used by WebKit and Safari.

JavaScript for Automation is built on JavaScriptCore.

It's using the modern JavaScript environment, and it's a kind of server-side JavaScript, or as we like to call it OS Automation JavaScript.

And while the underlying engine is the same, JavaScript for Automation is quite different from running scripts in your browser.

When you use JavaScript for Automation, you can do everything that you as the Mac user can do.

And this is very different from browser scripts that don't have access to your personal data or the applications on your Mac.

And in browser scripts you might expect a window object or a document object, but you're not going to have those here.

You have a host of different objects that you can interact with, to automate your Mac.

So how exactly was this brought to JavaScript?

Well to recap, applications have scripting dictionaries that detail what can be interacted with and how, and Apple events are used to communicate with those applications.

So to bring this to JavaScriptCore we built the JavaScript Apple Event Bridge that reads those scripting dictionaries and then uses Apple events to communicate with the applications.

So now that we've seen what JavaScript for Automation is and how it works, let's look at how we can use JavaScript for Automation, beginning with scripting applications.

We introduced an application object into a JavaScript context, which is the main entrance point to all of the scriptable pieces and parts of an application.

So, the most common way to access an application is by name.

Here we're accessing the Safari application.

And beyond name we can also access applications by Bundle ID, by Path, by Process ID, and we can get the application that's running the script we're currently in by getting the current application.

So now that we have this application object, we're going to want to interact with it.

Let's look at some examples of the syntax for doing just that.

Accessing properties is accomplished using dot notation.

To access elements, you use square brackets.

To call commands, you call them as functions using parentheses.

And you can create new objects by calling class constructors as functions, again, using parentheses.

So let's take a look at getting and setting properties.

Let's say we're scripting Safari, we create a reference to the first document of Safari, and now we can do things like get the document's URL.

See the parentheses at the end?

We're calling this property as a function because we want to actually send the get event to the application and get the string value.

We don't simply want to reference to the URL of the document, we want to call it as a function and get that string value.

We can also set the document's URL, and this sends the set event to the application and actually sets the URL.

Let's say we want to get a particular window in Safari.

Well, there are three ways to access elements in JavaScript for Automation: by index, by name and by ID.

Each has benefits and risks associated with it and it's important you understand the Object Model of the application that you're scripting to know when it's best to use which.

So already with just these basics we can do some pretty amazing things.

Let's put it to use.

First, I'd like to just open up Script Editor.

We've got a little JavaScript here, just straight JavaScript.

Creating a string, some text, and then I'm going to use console.log, just like I expect in JavaScript, to log this text.

And when I log this, it's going to show up in the event log on a lower panel.

So I'm going to open the event log, and if I run this script we see "hello world" was logged just like we wanted.

This is great.

This is the JavaScript I'm used to.

It's doing exactly what we wanted.

This is hugely useful for debugging, we can log throughout a script to see what's going on.

But let's say I wanted to write some text and I wanted it to exist even after I quit Script Editor, or perhaps I want to style that text, change its font or color and so on.

Now we can start interacting with applications to accomplish that.

So here we have a TextEdit document named Log, and I'm going to use this across a couple demos to write some text.

First, this is a simple script, we access the TextEdit application, we get a reference to the Log document, then we set the document's text and we style its font, size and color.

So before I run this I'm going to open the Event Log and we'll be able to see the events that are being sent to this application to accomplish this.

So when I run this script, we see "I love JavaScript" was logged just like we wanted, styled just liked we wanted, and in the bottom here we see all of the events that were sent to accomplish this task.

So this is great, we have some persistent text, it's been beautified just like we wanted.

But what if we want to do this multiple times from the same script?

Well, instead of repeating the functionality again and again, we're playing in JavaScript, we can write a function.

And I've done just that.

Here we have a function that accepts some text to log and an optional formatting parameter.

Then, just like before, we access the TextEdit application, we get a reference to the log document, but now instead of setting the document's entire text, we're going to append to the last paragraph.

Then we're going to style based on formatting you pass in or some default values.

Now that we have our log, we call it three times at the bottom here, passing in parameters for formatting twice, and the last time we use default values.

So if I run this script, we see that our text was logged just like we wanted, styled as we wanted.

And this is great, we're able to log as many times as we want, style any different way that we choose, every single time.

So this is powerful stuff simply by accessing an application, an element, and a couple properties, right out of the box, power at your fingertips, and it's really easy to approach.

Let's look at some other ways that we might want to interact with applications.

Let's say we're scripting Mail and we want to access some of the messages in our inbox, but we don't want the entire messages element array of the inbox, that's a whole lot of messages usually.

Let's say we want to get only the messages whose subject is JavaScript.

Using the special "whose" method of element arrays we can do just that.

By passing in a dictionary of properties we'd like to match on those elements we now receive an array only containing the elements that match.

Objects have certain commands that they can respond to and you can call those commands as methods locally that send the command events to the application.

So again, let's say we're scripting Mail, we have a reference to the first message of our inbox, and we want to open it.

Well, we could tell the message to open, we could also tell Mail to open the message.

And both of these are entirely equivalent.

Some commands take named parameters, and so you accomplish this by passing in a dictionary of those named parameters.

Here, for example, we're creating a reply to our message, we're going to reply to everybody and we're not going to open a window.

Now remember, you can always use the dictionary viewer in Script Editor to see which named parameters go with which commands, which commands can be called on which objects, and so on.

It's a phenomenal tool and really useful when you're building more complex scripts.

Some commands take files as parameters, such as opening a document using TextEdit.

So to accomplish this we've introduced a path object into the environment that you construct with a string that has a string with a file path inside and now you can use that path object anywhere that a file is expected as a parameter.

So we could open our document just like we wanted.

Be aware that if you pass a string instead of a path wherever a file's expected, you will receive an error.

So let's say we want to create a document instead of simply opening one in TextEdit.

Well, we're scripting TextEdit, we can call the document class constructor as a function.

But now to actually create this object inside the application, bring it to life, we're going to push the document onto the documents element array.

And that actually creates it inside the application.

Then we can interact with it just like any other objects inside the application.

We can set its text, for example.

And optionally, when you create objects, you can pass in a dictionary of properties you'd like to have set on that object when it's created.

Here we're creating a document, passing in some text when we instantiate it.

We push again on the appropriate array, and it's created inside the application, living and breathing, ready for us to interact with.

So this is a wide range of functionality, inherently available in applications, property access, element access, calling commands, creating objects.

But there are script plug-ins, plug-ins for scripts that allow you to extend the functionality of an application.

And the OS has a set of standard scripting additions that it ships.

These are available from every scripting environment, including JavaScript for Automation.

So let's say that we're scripting the current application and we want to be able to use these standard additions.

To do so we're going to set the includeStandardAdditions flag to true, and then we can do things like tell the application to beep, which is hugely useful for debugging, tell the application to speak some text, which can extend our functionality to a wider audience.

We can also do things like display alerts and dialogues, which is great because now we have user interaction incorporated with scripting applications.

So we've covered a lot of different ways that we can actually script applications, their Object Models, and so on.

Let's look at other uses of JavaScript for Automation.

Remember earlier when we racked the logging functionality in a function so we could use it multiple times from one script?

Well what if we wanted to log from multiple scripts, not just one?

This is the perfect use of a library.

I've taken that log function and I've saved it in a script named Toolbox in the Script Library's folder.

And now I can access this library and its functions from any other script that I write.

To accomplish this I instantiate a library object by name, and file extension is optional, and then I can those functions as methods on that library object.

So this code would log just like we did before.

And the beautiful thing about Libraries is they can be written in JavaScript and Apple Script, and used in JavaScript for Automation.

So now let's take a look at how to create applets using JavaScript for Automation.

Applets are applications saved by Script Editor, and when you run an applet the script that's saved inside is run.

Applets have a certain number of events that you can create handlers for, such as when the applet is run, when the applet is told to open documents or print documents.

There's a special idle handler that allows you to perform periodic tasks.

And you can also create handlers for when an applet is reopened, or when an applet is quit.

And just like Libraries, you can have any other functions inside your applet and those can be called.

So let's take a look at an example of a basic applet that uses a Script Library.

Here we have our log document like before, and let's look at the script inside of this applet here.

At the top we instantiate our Toolbox Library, then in our run handler we log Run in green.

In our idle handler, we log Idle in orange.

And in quit handler, we log Quit in red.

So if I double click this applet to run it we see that Run and Idle were logged just like we wanted, and if I go and quit the applet, we see that Quit was also logged, which is great.

This is exactly what we wanted.

And this is a very basic example of using a couple handlers and an applet and using a Library.

But imagine the possibilities here.

This is double-clickable JavaScript sitting on my desktop, ready to interact with all the scriptable applications, Script Libraries and more.

Speaking of more, we've looked at scripting the Object Model of an application extensively, but what if we want to script the user interface of an application?

This is accomplished by using accessibility, which allows applications on your Mac to interact with your Mac on your behalf.

System Events uses the accessibility APIs to expose the user interface of an application.

And in JavaScript for Automation, you use the System Events application to access the pieces and parts of a user interface.

So let's look at an example.

First, we're going to access the System Events application.

Then we're going to access the Notes process of the System Events processes elements array, and we're going to set it to a variable, notesUI.

Now we can do things like close a window, by clicking the first button of the first window of Notes user interface.

Let's say we want to send some keystrokes to this application.

Well to do so, we're going to access the Notes application itself and activate it, bringing it to the front, and then we could call the SystemEvents.keystroke command, passing in 'm', using 'command down' to simulate a minimize event.

To use accessibility it must be enabled in the Privacy preferences, for applications like Script Editor, and so on, to use it.

And the first time you try to use it, accessibility, you will be prompted to enable it.

Okay, so we've looked at another way to script an application, its user interface.

We've looked at scripting Object Models, Libraries, and Applets.

Now let's look at a more advanced use of JavaScript for Automation using system APIs, which provide access to really powerful and important things like the file system and Cocoa app development in JavaScript.

We introduced two objects into the environment that are your means for interacting with system APIs.

ObjC and $.

And for those coming from a browser environment, $ may mean something very special to you, but in our environment it's a very different $.

ObjC can be used to do things like bridging JavaScript values into Objective-C, bridging Objective-C objects into JavaScript, and importing frameworks that you'd like to use.

So once you've imported a framework you can access its classes and functions and so on using the $ object, and you can also call $ as a function, as a shorthand for bridging JavaScript values into Objective-C.

So now let's talk about calling methods on objects.

Well, to begin let's look at some Objective-C code.

It's quite simple, we're going to create an NSString and then we're going to write that string to a file.

This is the equivalent JavaScript for Automation code to accomplish this.

And there are a couple key things to focus on here.

First, the Foundation Framework is available to you out of the box when you're using JavaScript for Automation.

So we don't need to import Foundation.

Then, we use the $ object to access the NSString class, we call alloc, and because it takes no parameters, we don't need parentheses.

We do not use parentheses here.

Then, we call initWithUTF8String, and we're going to be passing in a parameter, so we call it as a function and pass in our parameter.

Now, the method to write to a file takes multiple parameters, so we're going to convert the selector to a JavaScript method name, that can catenating and camelCasing the pieces together, and then we call it as a function, passing in the parameters in the right order.

So now that we've seen how to write to a file, let's actually see it in use.

This is a little script.

At the top we create an NSString with some text we'd like to write to a file.

Then we create an NSString with a file path, and we call this stringByExpandingTildeInPath method on it to get the full path.

And then we write the string to that file.

And when we write this, it's going to appear in this folder here.

So if I run this script, our file was created, our text was written just like we wanted.

This is phenomenal.

And this is a simple example, but you can imagine the power and utility that the system APIs bring to the JavaScript for Automation environment.

Let's look at other ways that we can interact with these API's.

Let's say we create a new NSTask object.

Well, to access its properties we're going to use dot notation.

So we can access the running property, get its Boolean value and react accordingly.

We could also set its launchPath property, like so.

This will actually set it on the object.

An interesting thing of a JavaScript for Automation bridge, is the bridged nil.

So, nil in Objective-C is somewhat similar to the undefined in JavaScript, but they're not exactly the same, and they differ in key ways.

In Objective-C it's absolutely valid to call a method on a nil object, and you'll receive another nil object.

But in JavaScript, if you call a method on an undefined object, you will receive an error.

Therefore, we do not bridge nil undefined, we keep it as a bridged nil object that you can interact with.

So to create a bridged nil object, we call the $ function without any parameters.

Why might you want to create a bridged nil object, you're asking?

Well, this allows you to accomplish things like pass-by-reference.

So here we're creating a new NSXMLDocument, and we're going to pass our bridged nil object, our error variable, as the third and final parameter.

And what'll happen behind the scenes is if an NSError object is created, the bridged nil object will be replaced by it, and now our error variable will point at that and we can use that.

So once we've created our document, we can check if it's nil by calling the isNil method on it, and if it is nil we could, for example, log the user info from the now populated error object.

Another exciting thing that you can do using system APIs is subclassing objects.

So to accomplish this, you call the registerSubclass method on the ObjC object, you pass in a name of your Subclass, its superclass, although this is optional, and will default to NSObject, any protocols that your class made here, too.

Properties are defined as an object where the keys are the names of the property and the values are the type of the property.

And methods are, again, an object where the keys are the selector and the value is an object detailing the types of the method and its implementation.

Now if you're defining a function or a method, excuse me, that's declared in a protocol or on a superclass, the types are optional, but for demonstration purposes we'll show them here.

So now let's put this to use.

Let's see using a subclass and creating something using system APIs.

So here I have an applet, and this is the script inside, and this produces a Cocoa application, a temperature converter, nice little guy for us to use.

And there are two things I'd like to point out before we actually run this.

You'll see at the top that we import Cocoa.

Now this allows us to access things like NSWindow, and so on.

We create our windows and our inputs, and then we register our subclass, named TemperatureConverter, that has two methods, to convert from Celsius to Fahrenheit, and from Fahrenheit to Celsius.

And you can see that all of the logic inside of these methods, all of the math is in JavaScript.

Then we create a new TemperatureConverter object, hook it up to our inputs, and bring the window to the front.

So let's run this.

Close this here, and if I double click this Applet to run it, we have a nice little Cocoa application written entirely in JavaScript.

[ Applause ]

Of course, it does what we promise.

We can convert our Fahrenheit to Celsius, our Celsius to Fahrenheit and so on.

And this is a little example.

Look at this.

We can create a Cocoa application in JavaScript, imagine what you can do from here.

With all this at your fingertips, there is power ready to be used.

And definitely make sure to check out the JavaScript for Automation for release notes, where you can see other great things you can do using system APIs, like binding C functions into the environment, another mechanism for pass-by-reference, and also passing functions where blocks are expected.

All right, so we've done a beautiful whirlwind tour of all the ways we can use JavaScript for Automation, from application scripting, libraries and applets, UI scripting, using system APIs.

I'm sure each and every one of you is just itching to get your hands on this.

I completely understand.

But before you do let's talk about where you can use JavaScript for Automation.

So as all the demos have shown, you can use JavaScript for Automation in Script Editor.

You can save Applets and Droplets from Script Editor, as we saw, and run them.

As Sal mentioned, and you saw in the presentation demo, you can save scripts in the system-wide Script Menu, and this is phenomenal for scripts that you're going to use repeatedly, again and again.

Automator, which allows you to produce workflows, automating applications and processes on your Macs, now has a run JavaScript Automator action that lets you incorporate JavaScript for Automation into your workflows, and once you've done so you can save those workflows as services that can be used from any application and across your system.

And finally, you can use JavaScript for Automation in Terminal using the osascript command line tool.

And this is great, you can incorporate JavaScript for Automation into a Bash script.

And for example, display an alert when you're about to finish a long-running background process.

So we've seen some of the places where you can use JavaScript for Automation already, now let's look at the rest.

Let me set the scene, I work as a photographer in a travel magazine and I take pictures for our cover.

And every week I have to send those cover photos to the same person to be approved before I can submit them the print.

Every week I sent the same email message to the same person and all I'm changing are the pictures.

So, I whipped up a little droplet here using the openDocuments handler that accesses the mail application, creates a new mail message for us using some pre-canned content.

It then uses the Contact application to get my recipient of the email message, gets their name and their email address, puts it on the message, and then for each of the pictures that we've dropped on this droplet we're going to add them as attachments to the message, activate mail and have it ready to send whenever I'd like.

So, here are some of the photos I took.

I happen to know the last three are the most beautiful, so I'm going to drop those right here onto this droplet.

Our mail message is created, the content's there, our recipient's there and all the pictures we wanted are ready for us to go.

My workflow was cut from 100% down to 5, 10, 0%.

This made my life easier.

And while I have this script open, I'd like to mention another problem that I have.

I read a lot of JavaScript for Automation, as you might expect, and I regularly have Script Editor windows open, multiples all at once.

Sometimes I'm running a Library that I'm going to use in another script and I want to be able to see everything at the same time.

And so before I hopped on the Automation train, I might've had to drag these windows around the screen, resize them, make sure corners aren't overlapping each other, and so on and so forth.

But then I realized, why don't I automate it?

So I whipped up this script here that accesses the Script Editor application, it gets all of the windows, and then using the number of windows and the size of the screen it carefully, meticulously, programmatically tiles the windows around the screen, based on their size.

So if I run this from the script menu, because I use it so frequently, we see all of my windows were tiled exactly as I wanted.

I can see everything all at the same time.

This is beautiful for developing multiple scripts at the same time.

So I used JavaScript for Automation to make writing JavaScript for Automation even easier.

It's powerful, it's flexible and it's everywhere.

[ Applause ]

Now, speaking of flexibility, and power, and everywhere, in fact, we've proven to ourselves how easy it is to extend popular Text Editors for JavaScript, like Sublime Text, and TextMate, to extend and to execute JavaScript for Automation code that we're writing in those applications.

And to prove it to you how easy it is to write JavaScript for Automation anywhere and run it, we've whipped up this automated workflow that uses the new Run JavaScript action, and what we do is we access the content of the front-most document, we evaluate that as a script, then we display the result and we optionally copy it to the clipboard if we'd like.

I've saved this as a service and I've attached that service to a hotkey, so now my work is very, very slim and easy to do.

I would like you to notice I'm in TextEdit right now and I have JavaScript for Automation code written in a document.

So using that Automator workflow as a service attached to this hotkey, I can run this, code executing from the TextEdit IDE that I love so much, that I've created using JavaScript for Automation.

We get our result, we could copy to the clipboard but not right now, thank you.

And so, that's amazing.

I just run JavaScript for Automation from TextEdit, and this is to show that you can use JavaScript for Automation how you'd like, where you'd like.

It's extraordinarily extensible and it's extraordinarily flexible.

And as we mentioned before, you can use JavaScript for Automation from Terminal using the osascript command line tool.

So, let's look at an example.

We're going to be calling the osascript command line tool with a couple flags.

We're going to be using the JavaScript language.

We want our result to print a source, and then we pass in some JavaScript to run.

This is what I talked about before.

We can display an alert, so imagine this could be a part of a bash process at the end that'll show us an alert when our process is about to finish.

So if I run this, our alert was displayed just like we wanted, which is great.

We get our result, we could react accordingly if we wanted.

And another really exciting new feature of osascript is an interactive mode.

So a variety of programming languages, like Ruby and Python, have interactive modes that allow you to interactively program in those environments, and now this is possible from osascript.

So, to do so I'm going to call osascript, our language is JavaScript, and I'm going to pass the -i flag to say I'm going in interactive mode.

Now to demo this interactive mode, I'm going to be interacting with Safari.

So, I'm going to create a variable and set it to the Safari application, we see that Safari was activated for us, making it a little better to see.

Then we can do things like create a reference to the first window.

Let's say we want to get that window's name and simply call the name property as a function.

Favorites, like we expect, that's great.

This is a lot of fun, but let's spice it up a bit.

Let's create a new tab and add that to the window in real-time, interactively.

First, we'll create a new tab, and we'll have the URL be

Then, to actually create this in the application I'm going to push it onto the window's tabs element array.

And, before I do though, I know that I want to bring the tab to the front when I do this, and I can't quite remember, I think it's the front tab or there's a property that I can summon a window to bring it to the front.

So, we're interacting with this live, before I do this let's make sure that I know what I'm doing.

So I'm going to bring up Script Editor and I'm going access the Library window and let's see, we'll access Safari scripting Dictionary.

Great. Okay, we'll look at the Safari suite.

Yes, window, thank you, ah, the currentTab, not the frontTab, excuse me.

So now that I have this property I know exactly how to create, how to set the tab to the current tab, bringing it to the front.

So if I push out of the array and bring the tab to the front we've just now live, interactively added a tab to this window, and had a whole lot of fun in the process.

[ Applause ]

And beyond being a cool way to interact with applications, this is phenomenal for exploring their scriptability, for learning JavaScript for Automation.

It's a great tool to have.

All right.

So we've covered what JavaScript for Automation is, how it works, how you can use it and where you can use it.

To summarize, JavaScript for Automation is built on JavaScriptCore, a modern JavaScript environment and it's built on the Open Scripting Architecture, which has been part of the Mac OS since before OS X.

JavaScript for Automation has been integrated system-wide at all layers, from high-level application scripting, to system services, to use in the terminal, and accessing system APIs.

And as you saw, JavaScript for Automation is flexible, it allows you to accomplish tasks and solve problems the best way that you see fit.

So, our call to action today is go out and script the scriptable applications on your Mac.

For app developers, make your applications scriptable so other people can script them and do amazing things.

And make sure to tell others to make their applications scriptable if it isn't already.

We have a phenomenal ecosystem, we're really excited for more and more applications to join it every day.

To check out documentation, make sure to go to, for the JavaScript for Automation release notes, as well as some sample code.

We are having a phenomenal time with this great new feature, we cannot wait for you to get your hands on it.

Thank you very much.

[ Applause ]

Apple, Inc. AAPL
1 Infinite Loop Cupertino CA 95014 US