2

I basically want to port this code from AS to JXA:

tell application "Finder"
    close every window
    open folder "Projects" of folder "Documents" of home
    tell the front Finder window
        set the bounds to {0, 0, 1920, 1080}
        set the current view to list view
    end tell
end tell

Thanks in advance! There is so little information about JXA out there!

Maximilian Ast
  • 3,369
  • 12
  • 36
  • 47
Reydel Leon
  • 1,035
  • 2
  • 11
  • 34

3 Answers3

3

To close all Finder windows, the script need a loop:

finder.finderWindows().forEach(function(w) {w.close()})

or

var allWindows = finder.finderWindows()
for (var i in allWindows) {allWindows[i].close()}

or with the map method:

var finder = Application('Finder')
finder.finderWindows().map(function(w){w.close()})
finder.home.folders["Documents"].folders["Projects"].open()
finder.finderWindows[0].bounds = {"x":0, "y":0, "width":1920, "height":1000}
finder.finderWindows[0].currentView = 'list view'
jackjr300
  • 7,111
  • 2
  • 15
  • 25
2

This one-liner will close every Finder window:

with (Application('Finder')) close(windows)

You could implement the full script like this:

f = Application('Finder')
w = f.windows.first

f.close(f.windows)
f.open(f.home.folders["Documents"].folders["Projects"])
w.bounds = {"x":0, "y":0, "width":1920, "height":1000}
w.currentView = 'list view'
bacongravy
  • 893
  • 8
  • 13
0

The following should work:

Application('Finder').windows.close()

Alas, JXA is made of Lame and Fail † so just throws an error when you run it, so you'll have to use a loop to close each window one at a time.

You do need to be careful though when iterating over an array of object specifiers, as only by-ID specifiers are guaranteed to be stable. (Remember: object specifiers are first-class queries, not pointers, so behave very differently to OO-style references.) On this occasion, jackjr's finder.finderWindows().forEach(function(w) {w.close()}) will do the job, because finder.finderWindows() returns an array of by-ID specifiers. However, if the array contains by-index specifiers then you must iterate those specifiers from last to first or else you'll get off-by-N errors.

† (TBH, for any non-trivial automation work, you're best sticking to AppleScript. The language itself may be crap, but it's the only currently supported option that actually speaks Apple events right.)

foo
  • 3,171
  • 17
  • 18
  • Yeah, I tried that before asking this question here. It seemed to me the most logic way to go, but it didn't work. After trying every possible way I could think off, I gave up and came here. I didn't want to go with the loop route, since it seemed to me there would have to be a better way. – Reydel Leon Feb 12 '16 at 05:43
  • I can confirm bacongravy's version works. `app.specifier.command()` is just a convenient synonym for `app.command(specifier)`, but like a lot of things in JXA it only works up to some random point, whereupon it magically breaks and you've _no_ idea why. Stupidly frustrating and idiotically broken, with useless user documentation and zero official support. Honestly, I'm not kidding when I say you're better off sticking to AS if you can: the language may be junk but at least it's got an established user community that understands it and is alway happy to help. – foo Feb 12 '16 at 14:29
  • p.s. The other big reason you can't get info on JXA is because I scrapped all my plans to write a book on JXA automation due to it being so badly borked. I already did one book on [AppleScript](http://www.amazon.com/Learn-AppleScript-Comprehensive-Scripting-Automation/dp/1430223618/) which damn near gave us a nervous breakdown – and JXA is even more screwed up than AS. And I'm about the only person who actually understands this stuff well enough to explain it right (an even more depressing thought!) so don't hold your breath either. Such a wasted opportunity. :( – foo Feb 12 '16 at 14:47
  • In this case, the behavior is neither random or magic; JXA just doesn't support calling commands on [element arrays](https://developer.apple.com/library/mac/releasenotes/InterapplicationCommunication/RN-JavaScriptForAutomation/Articles/OSX10-10.html#//apple_ref/doc/uid/TP40014508-CH109-SW9). Instead, JXA uses property access on element arrays as shorthand for name and index lookup. In JavaScript, `windows.close` and `windows["close"]` mean exactly the same thing, so when you try to call `close()` on an element array of `windows`, JXA tries to get the window named "close", as documented. – bacongravy Feb 20 '16 at 18:54
  • _"JXA uses property access on element arrays as shorthand for name … lookup"_ -- Actually it uses it to construct both property/elements specifiers __and__ by-name selectors. Which creates a mind-numbingly stupid conflict in itself. e.g. Is `textedit.documents.text`, aka `textedit.documents["text"]`, a reference to the text of all documents, or to the document named "text"? And why can you say `documents.text()` but not `documents.close()`? JXA is rife with this sort of impenetrable stupidity. (And yeah, I wasted weeks of my time flagging all these problems back when JXA was announced.) – foo Feb 21 '16 at 16:56
  • BTW, there's no such thing as "element arrays". The JXA documentation is junk. The Apple Event Object Model is a relational graph, __not__ an OO tree like DOM. Each node in an AEOM graph has its own attributes (slots that hold simple values like strings and numbers describing that node's state), and can have any number of _one-to-one_ and/or _one-to-many relationships_ with other nodes. Here's a [somewhat rough overview](http://hhas.bitbucket.org/understanding-apple-events.html), and here's [a paper](http://www.cs.utexas.edu/~wcook/Drafts/2006/ashopl.pdf) by its original designer. – foo Feb 21 '16 at 17:06