What to know about the AppleScript changes in OmniFocus 2

We’ve maintained backwards compatibility where we could, but there’s a lot of changes.
Here’s some notes direct from our primary AppleScript developer about what you should be aware of as you update your OmniFocus scripts.

(Please feel free to start new threads with specific scripting questions.)

  • AppleScript is supported only in the Pro edition of OmniFocus.

  • Our rich text class is now called rich text instead of text, matching other applications on the system. Compiled scripts should continue to work. The AE code is now 'OSrt' with an synonym of ctxt. Other apps do other things:

    • Apple apps:

      • Xcode.app rich text/'ricT'
      • AppleScriptKit.framework rich text/'ricT'
      • iChat rich text/'rtfx'
      • Mail rich text/'ctxt'
      • Aperture rich text/'ctxt'
      • TextEdit uses scriptSuite/scriptTerminology and ends up with text/'ctxt'
    • AppleScript related apps:

      • Script Debugger.app rich text/'ricT'
      • FastScripts.app rich text/'ctxt'
    • Omni apps (already changed via OmniStyle.sdef):

      • OmniPlan rich text/'ctxt'
      • OmniFocus rich text/'ctxt'
    • Other apps:

      • Scrivener rich text/'ctxt'
      • PDFpen rich text/'ctxt'
      • VoodooPad rich text/'rtfx'
      • Adium rich text/'ricT'
      • Acorn rich text/'ctxt'
  • In order to work with application sandboxing, file or POSIX file must be used for saving and opening instead of passing strings as file paths.

  • When making a new document with AppleScript (a fairly rare operation, except for our testing scripts), a file property must be specified.

  • The name of documents is now the display name instead of the last path component (including the path extension). This means that name based lookups need to not include the path extension. Additionally, name based lookups are case- and diacritical-insensitive.

  • The file name property of the file attachment must be a file or POSIX file due to sandboxing.

  • The autosave interval property on document has been removed.

  • The value property on the attribute class now returns a generic color record for color-typed attributes. This is a record with specific components, including alpha (with numeric components ranging from 0 to 1).

  • The regexp argument of the replace command has been named regular expression and given a new type code so that old scripts using that form will neither compile or execute. The format of this regular expression is now based off the ICU syntax used by Apple’s frameworks.

  • The select command has been removed. Instead the add, remove, and set commands can be used to update the selected trees element.

  • Added the pbcopy, pbpaste and pbsave commands to copy items to and from the pasteboard.

  • The library and inbox properties have been removed from the sidebar tree class.

  • The document window class now has a selected sidebar tab property.

  • The selected view mode identifier property on document window is gone, replaced by the selected sidebar tab property. The available view mode identifiers property is also gone as the available list of tabs is described by the type of the selected sidebar tab property.

  • The available smart group identifiers and selected smart group identifier properties on sidebar tree don’t map directly to the view settings set up by the interface and are deprecated (marked hidden, but still in the suite). If you need scripting access to the view settings, please let us know what we are trying to accomplish so we can add appropriate access.

  • The import command has been replaced by the import into command, which specifies the destination document explicitly. Additionally, this now takes a file typed parameter for the from argument.

  • The parse tasks command has been replaced by the parse tasks into command, which specifies the destination document explicitly.

  • The code for default value on the style attribute class has changed from ‘OSdv’ to ‘OFdv’. Scripts using this terminology may need to be recompiled.

Seems like there are no notes around changes to:

  1. windows (id 1 is now id -1).
  2. first window is entirely broken.
  3. content no longer exists on window, but is on document window.
  4. Tree access seems to a list of list, even when asking for leaves
  5. The value of said leaves don’t seem to be proper tasks, because they respond with missing value to name.

Some examples:

What was:

leaves of content of first window whose note of value of it starts with "http"

is now

leaves of content of document window of default document whose note of value of it starts with "http"

And this

class of value of leaves of content of document window of default document

returns

{{task, task, task, task, task, task, task, task, task, task}}

but this

name of value of leaves of content of document window of default document

returns this

{{missing value, missing value, missing value, missing value, missing value, missing value, missing value, missing value, missing value, missing value}}

Without complete change notes, I’m stabbing in the dark trying to get my workflow to work at all again.

None of these are intentional changes, but look like either changes out of our control or bugs that didn’t get found during the beta period (and so the release notes don’t list them).

On window vs. document window, I’m surprised the first form ever worked. This smells like something due to our switch to sdef, or updates in AppleScript itself enforcing types more strongly.

The failure of name of value..., I don’t seem to be able to reproduce the same issue. When I run OmniFocus 1.10.6, select a project in the sidebar in Project mode and run this script:

tell application "OmniFocus 1.x"
	name of value of leaves of content of document window of default document
end tell

I get:

{missing value, missing value, missing value, missing value, missing value, missing value, missing value, missing value, missing value, missing value}

Perhaps there is some step I’m missing? Of course, I would agree it would be better for the names to be returned here in both versions of OmniFocus, but I’d like to make sure I test and fix the case you are hitting too.

Thanks, Ryan!

Here’s some code I have for OF1:

tell application "Safari"
	activate
	
	tell application "OmniFocus"
		set noteNodes to leaves of content of first window whose note of value of it starts with "http"
		-- OF2: set noteNodes to leaves of content of document window of default document whose note of value of it starts with "http"
		
		set urls to {}
		repeat with node in noteNodes
			if name of node contains "Triage" then
				set selected of node to true
				set end of urls to note of value of node
			end if
		end repeat
	end tell
	
	make new document
	
	repeat with aUrl in urls
		make new tab at end of window 1 with properties {URL:aUrl}
	end repeat
	
	delete tab 1 of window 1
end tell

This will open up a safari tab for every task I have that has a name of “Triage X” and a body with “http” at the start. It works great in OF1. In OF2, I have to make the one commented code change, and I have to put an extra “value of” for the name check… but I still am not enumerating the leaves right. leaves of tree should always be a single level list IMO. Is there something I’m not getting? Maybe there needs to be more types like flattened leaves if it is maintaining the tree structure at the leaf level?

Yeah, the nested list for leaves is a bug – it seems to be happening in the depths of AppleScript, but something about our sdef might be funky and provoking this. We’ll take a look!

1 Like

After looking into this, it seems this isn’t actually a bug, though a bit unexpected.

OmniFocus can have more than one document window per document, so the specifier leaves of content of document window of default document whose note of value of it starts with "http" is getting interpreted to run that qualifier on every window of the document, and since you asked for it in array form, the results are getting collated by window. For example, if you create two windows, you’ll get back {{... results for window 1...}, {...results for window 2...}}

The unexpected part here (to me, at least) is that the bare document window specifier is not spelled out as every document window, making it more clear that there are multiple things being queried.

In your case, you probably just want the front-most document window, so if you say 'document window 1orfront document window`, you should get the expected results.

1 Like

Thought I’d mention something not covered here…

I have a script to create tasks from mail messages that are in a specific folder. Its super quick to drag email into the folder, or send to a certain email address, to have it put into Omnifocus automatically.

I only run the script if OmniFocus and Mail are running, so the script referenced the bundle identifier com.omnigroup.OmniFocus. But this now becomes com.omnigroup.OmniFocus2.

tell application "System Events"
	set isOmnifocusRunning to (count of (every process whose bundle identifier is "com.omnigroup.OmniFocus")) > 0
end tell

Needs to be updated to:

tell application "System Events"
	set isOmnifocusRunning to (count of (every process whose bundle identifier is "com.omnigroup.OmniFocus2")) > 0
end tell

I moved a post to a new topic: Attaching a file via script

Any examples of how this works? I’ve found someone using this to clear selections (see here) but can’t figure out how to actually select something.

Here are some examples of changing the selection via AppleScript:

tell first document of application "OmniFocus"
    tell sidebar of first document window
        set selected trees to every tree -- Select everything
        set selected trees to {} -- Select nothing
        set selected trees to {tree "Mac", tree "iPhone"} -- Select "Mac" and "iPhone"
    end tell
end tell

Hope this helps!