Original goal:
- open a web page and automate the process of selecting "export to PDF..." from that page.
Resources that helped significantly:
- Getting Started with JavaScript for Automation on Yosemite
- A Beginners Guide to JXA, JavaScript Application Scripting
- Automation for OS X: the JavaScript way
- JXA Cookbook wiki
- JXA release notes archive
Introspecting the application views and UI elements quickly became the hardest component.
I tried inspecting through a number of avenues, including the debugger context that could be opened from Automator, XCode's accessibility inspector, and various archived documentation sources. In the end, what seemed to provide the most context was interactively requesting "what's in the view" from a terminal prompt:
osascript -l JavaScript -i
And then interactively in javascript:
// working with safari's available extensions
var appSafari = Application('Safari');
appSafari.Document().make();
appSafari.windows[0].currentTab.url = "https://apple.com/"
appSafari.activate()
// working through system accessibility to interact with safari
var se = Application('System Events')
var browser = se.processes.byName('Safari')
function clickMenuItem(processName, menuName, menuItemNames, interval) {
//function logTitles(menuItems) {
// for (var item, i = 0, j = menuItems.length; i < j; i++) {
// item = menuItems[i];
// console.log(item.title());
// }
//}
interval = interval || 0.5;
let process = se.processes.byName(processName);
let menu = process.menuBars[0].menuBarItems.byName(menuName);
menu.click();
delay(interval);
let previousMenu = menu;
//logTitles(previousMenu.menus[0].menuItems);
for (let menuItemName of menuItemNames) {
let menuItem = previousMenu.menus[0].menuItems.byName(menuItemName);
menuItem.click();
delay(interval);
previousMenu = menuItem;
}
return previousMenu;
}
clickMenuItem('Safari', 'File', ['Export as PDF…']);
delay(0.5)
// inspection function from <https://stackoverflow.com/questions/38290690/applescript-iterate-uielements-using-javascript>
function iterate(obj) {
for (var i in obj) {
if(obj[i] instanceof Array) {
iterate(obj[i])
} else if(obj[i] instanceof Object){
console.log("Object: " + i + ': name = ' + obj[i].name() + ', value = ' + obj[i].value() + ', class = ' + obj[i].class() + ', description = ' + obj[i].description())
iterate(obj[i].uiElements())
}
}
}
// inspecting - this takes a while (several seconds) and generates a
// LOT of output.
browser.windows[0].entireContents()
// a pre-compiled version of this sort of thing is also available at
// <https://github.com/sancarn/Element-Scripter>
// other introspection tools:
browser.windows[0].properties()
browser.windows[0].attributes()
// get the front window of Safari
var winFront = browser.windows[0]
var frontSheet = winFront.sheets[0]
var saveButton = frontSheet.buttons.byName("Save")
//debugger
saveButton.click()