How to open database in current DEVONthink window via JXA?

I have built a JXA script that opens a database root.

The script currently opens the database in a new DEVONthink window.

How can I force the database to open in an existing DEVONthink window, if the app is already open?

I’m sure I’m overlooking something obvious, and am grateful for any advice. After searching around, I think I probably need to do something with ViewerWindow and selection, but I’m having trouble working out the JXA syntax.

My script looks like this:

// init methods for DEVONthink
const dT = Application('DEVONthink 3')
dT.includeStandardAdditions = true

// focus DEVONthink
dT.activate()

// get the database
const dTdb = dT.getDatabaseWithUuid("uuid-of-the-db")

// open the db root in a new window
dT.openWindowFor({record: dTdb.root() })

What seems to work here is

(() => {
const app = Application("DEVONthink 3");
app.openDatabase(absolutePathToDatabaseAsString);
})()

I’m not sure if that is what you want though: After executing the command, the DB is simply open when it was closed before.

But while fooling around with DT and JXA, I stumbled about this phenomenon:
When I try to list all databases (app.databases()...), DT only returns those that are open. Same for AppleScript. If that is intended behaviour, it should be mentioned in the documentation I think (@cgrunenberg ?).
How would one programmatically open all closed databases, for example?

You would need to provide each path, in AppleScript:

open database thisPath

You can set a window‘s root, in AppleScript:

set root of viewer window 1 to theGroup

To change it to the root of the desired database something like this should work, in AppleScript:

set theDatabase to open database "/abc/test.dtBase2"
set root of viewer window 1 to (root of theDatabase)

TX @pete31
That’s a bit of a catch 22: to open the database I have to know its path which I can’t get from the database unless it’s open. I can smell the logic behind it, but the documentation should state this behavior explicitly, I think.

this would translate to

const db = app.openDatabase("/abc/test.dtBase2");
let vw = app.vw();
vw.root = db.root();

not tested, though

Thanks @pete31 @chrillek , this is looking promising!

I’m still having trouble with the JXA however.

@chrillek, am I correct in thinking that app.vw() should be revised to app.ViewWindow()?

However, while this runs without error, the DEVONthink window is not updated to focus on db.root.

This seems very close, but I’m struggling to see why this isn’t working.

My code now:

// init methods for DEVONthink
const dT = Application('DEVONthink 3')
dT.includeStandardAdditions = true

// focus DEVONthink window
dT.activate()

// get the DEVONthink database for the selected project
const dTdb = dT.getDatabaseWithUuid("uuid-of-the-db")

// get the viewer window 
let vw = dT.ViewerWindow();

// set viewer window root
vw.root = dTdb.root();

I’ve also tried adding openDatabase after getDatabaseWithUuid

const dTpath = dTdb.path()

dT.openDatabase(dTpath)

Grateful for any more thoughts you may have.

Kind of: viewerWindow() - note the lowercase v!
Do you run the code in script editor? Then you can pepper it with console.log() statements. I suppose that vw is undefined.

thanks @chrillek, this is precisely one of the issues that is confusing me!

I too had thought that viewerWindow (lowercase v) would be the correct syntax.

However, it raises an error in the script.

I changed this to ViewerWindow (uppercase v) to match the class definition in the Script Editor Dictionary (but I may very well be wrong to do this).

But you are correct that while this returns an object [object ObjectSpecifier] it appears to be empty.

Is this syntax working for you?

I didn’t really try it before. What you describes matches my experiences now, though.
viewerWindow() throws an error, whereas ViewerWindow() returns an object. But setting this object’s root property to the root of a database does not do anything here. According to the code posted by @pete31, ViewerWindow should be a list (aka array). However, there’s no length property available on the object returned by app.ViewerWindow().

I think @cgrunenberg would have to comment on this. Although I did some JXA scripting with DT, I never tried to do what you do (which is to get where, exactly?). DT and JXA are not always happy with one another, and some parts of DT are not really working with JXA at all (or not as one would expect).
But maybe you don’t need all this viewer window stuff to achieve what you want to?

Thanks for your help with this, much appreciated!

I had wondered whether this was a failing on my part, or something more fundamental in the interaction between Applescript and JXA. From what I can tell, this seems to be relatively straightforward with Applescript, but as I’m adding this into a workflow automation that is entirely based in JXA, I was hoping there would be an easy way to translate. Hopefully @cgrunenberg can shed some light on whether or not this would be expected to work.

But maybe you don’t need all this viewer window stuff to achieve what you want to?

Do you have an alternative approach in mind? As mentioned in my original post, I have this working with the openWindowFor method but it opens a new window each time it is run. I’d be very interested if you can suggest alternatives to viewer window that might enable me to change the selection in the active DT window.

Given that I don’t know any context of this - no, I don’t. The automation I did with DT always centred on (selected) records, there was never the need to open a window. The only other thing I’m doing with JXA in this context is adding files to different databases/groups with Hazel. Also straigh tforward.

It’s viewerWindows, not viewerWindow. :slight_smile:

In my AppleScript example I used viewer window 1 as there’s no need to first get all viewer windows and afterwards item 1 of, at least not in AppleScript - don’t know about JavaScript.

This works.

// init methods for DEVONthink
const dT = Application('DEVONthink 3')
dT.includeStandardAdditions = true

// focus DEVONthink window
dT.activate()

// get the DEVONthink database for the selected project
let dTdb = dT.getDatabaseWithUuid("C06D2AA9-7453-4A6E-9A86-EDCF3B242A6F")

// get the first viewer window - no error checking included …
let  vw1 = dT.viewerWindows()[0];

// set viewer window root
vw1.root = dTdb.root(); 

1 Like

This actually works, thanks.

1 Like

Brilliant! Thanks so much @pete31 , @chrillek. This does indeed work. Appreciate your help (and patience) with this.

2 Likes