Quantcast
Channel: DEVONtechnologies Community - Latest posts
Viewing all articles
Browse latest Browse all 16117

JXA error with app.move()

$
0
0

Well, in that case your initials might also describe your feelings towards the smart rule I guess :wink:

Yes, osascript and Script Editor should be basically the same. But so should DT’s JXA scripting. Or, in other words, DT is using the same infrastructure as osascript and Script Editor. Therefore, an error occurring in DT and not in Script Editor/osascript is probably not directly related to DT.
Now, when I add your script as an internal script (that is, selecting “JavaScript” instead of “External”), it works just fine over here (with a minor amendment, see below).

You might want to look in the forum for sample scripts, for example using “performsmartrule” as a search term or “Application(” (don’t know if the latter works to find only JXA scripts.

When I said “dereferencing”, I was a bit off the usual terminology. JXA (as AppleScript) mostly works with “Object Specifiers”. Those are funny beasts. Usually, you don’t have to do anything about them if you just want to pass them on to JXA methods again. However, if you want to use them in JavaScript proper, things become interesting. JS doesn’t know sh*t (not my initials) about Object Specifiers. But it can (kind of) get at (some of) their internals by using function syntax on them. That’s what I called “dereferencing” before.
So, database.records is an Object Specifier, and you could (for example) use the JXA method whose with it like database.records.whose({name: "myname"}). You can also do database.records.length because length works with Object Specifiers. And even databases['Name of DB'], which looks like pure JS, works in JXA although databases is an Object Specifier.

But if you want to apply real JavaScript methods like forEach, you have to somehow™ convert the ObjectSpecifier to a JS object. That’s what the function call syntax does: you can do database.records().forEach(…), but database.records.forEach(…) will throw an error.

This conversion must also be applied to strings (console.log(record.name) will give you an error, while console.log(record.name()) prints the name.

It’s all a bit messy, yes. Rule of thumb: If you stay inside the JXA environment, i.e. you pass around things between apps or between methods of an app, do not “dereference”. If you want to work with something coming from JXA in JS, do “dereference”.

And then there are those border cases like the parameter to performsmartrule: That’s a list of Object Specifiers, aka known as Array in JavaScript. Therefore, you can do a records.forEach(r => ...). But then, each element of this Array is an Object Specifier. So, you have to write records.forEach(r => console.log(r.name())) to print out the name of every record.

You’ll find more on JXA on my website Scripting with JXA | JavaScript for Automation (JXA), also some DT examples

Now to the tiny amendment to your script. For my DT scripts, I tend to do this:

function performsmartrule(records) {
…
}
(() => {
  const appName = app.currentApplication.properties()['name'];
  if (appName !== 'DEVONthink 3') {
     performsmartrule(Application('DEVONthink 3').selectedRecords());
  }
})()

Rationale:

  • I don’t have to modify the source, the script figures out the environment it’s running in itself.
  • As the condition appName !== 'DEVONthink 3' is always true in a testing environment (aka Script Editor), the performsmartrule function is run with the currently selected record(s) in that context. That is, in my opinion, a lot more flexible than hard-coding locations etc.

Viewing all articles
Browse latest Browse all 16117

Trending Articles