“Actions” or “Tasks”

When interacting with the OmniFocus application’s user-interface (UI for short), you will encounter the term “Action” which refers to a new to-do item for a project. However, in the OmniPlan application, such a time-related element is called a “Task.”

The Omni Automation support in OmniFocus considers the terms “action” and “task” to be functionally synonymous, and refers to the scriptable element representing an “action” as a “task.”

In other words: a “task” is a something that needs doing, and “action” is the element in the OmniFocus interface that represents that need or to-do item. Scripts reference tasks, and the graphical user-interface of OmniFocus references actions. In the following documentation, consider tasks to be equivalent to actions.

Properties

An instance of the Task class is defined by the value of its properties.

IMPORTANT: some of these properties have values that are JavaScript date objects. An overview of some of the techniques for generating data objects in Omni Automation are detailed in the shared Date class documentation.

Task Properties Example

The following function uses multiple properties of the Task class to return “path string” detailing the parent hierarchy of the provided task reference:

"Smith Project ▸ Setup Task ▸ Preparation Task ▸ Gather Data Task"

Derive “Path” of Task


function getTaskPath(task){ getPath = function(task){ if (task.inInbox){ // inbox task return task.name } else if (task.project){ // root of project return task.containingProject.name } else { return getPath(task.parent) + " ▸ " + task.name } } return getPath(task) }

Task.ChildInsertionLocation Class

A location specified relative to an existing Task or Database. These cannot be instantiated directly, rather they are returned from properties like Task.before, Inbox.ending, or Project.beginning. (For a complete list of locations, open the API window navigation sidebar and use its filter to search for Task.ChildInsertionLocation.)

LOCATIONS: Inbox.beginning, Inbox.ending, Task.after, Task.before, Task.beginning, Task.ending, Project.beginning, Project.ending

Task.TagInsertionLocation Class

A location specifying the order of a Tag within a Task. These cannot be instantiated directly, rather they are returned from properties like <TagInstance>.beforeTag() or <TagInstance>.endingOfTags. (For a complete list of locations, open the navigation sidebar and use its filter to search for Task.TagInsertionLocation.)

LOCATIONS: <TagInstance>.beginningOfTags, <TagInstance>.endingOfTags

Ordering Tags


task = new Task("Tag Ordering Example") tagRed = flattenedTags.byName("Red") || new Tag("Red") tagGreen = flattenedTags.byName("Green") || new Tag("Green") tagBlue = flattenedTags.byName("Blue") || new Tag("Blue") task.addTag(tagBlue) insertionLocation = task.beforeTag(tagBlue) task.addTag(tagGreen, insertionLocation) task.addTag(tagRed, task.beginningOfTags) id = task.id.primaryKey URL.fromString(`omnifocus:///task/${id}`).open()

Examples

The following script shows how to drop a task:

omnifocus://localhost/omnijs-run?script=try%7Bvar%20win%20%3D%20document%2Ewindows%5B0%5D%0Avar%20tasks%20%3D%20win%2Eselection%2Etasks%0Atasks%2EforEach%28task%20%3D%3E%20%7B%0A%09task%2Eactive%20%3D%20false%0A%7D%29%7Dcatch%28err%29%7Bconsole%2Elog%28err%29%7D
Drop Selected Tasks
 

win = document.windows[0] tasks = win.selection.tasks tasks.forEach(task => { task.active = false })

The following script uses the dropDate property of the Task class and the flattenedTasks property of the Database class to revive tasks that were dropped since the start of the day (12:00 AM):

omnifocus://localhost/omnijs-run?script=try%7Bvar%20midnightToday%20%3D%20Calendar%2Ecurrent%2EstartOfDay%28new%20Date%29%0AflattenedTasks%2EforEach%28task%20%3D%3E%20%7B%0A%09if%20%28task%2EdropDate%20%3E%3D%20midnightToday%29%7B%0A%09%09task%2Eactive%20%3D%20true%0A%09%7D%0A%7D%29%7Dcatch%28err%29%7Bconsole%2Elog%28err%29%7D
Un-Drop Tasks Dropped Today
 

cal = Calendar.current now = new Date() midnightToday = cal.startOfDay(now) dc = cal.dateComponentsFromDate(midnightToday) dc.day = dc.day + 1 midnightTomorrow = cal.dateFromDateComponents(dc) flattenedTasks.forEach(task => { tdDate = task.dropDate if (tdDate >= midnightToday && tdDate < midnightTomorrow){ task.active = true } })
omnifocus://localhost/omnijs-run?script=try%7Bvar%20cal%20%3D%20Calendar%2Ecurrent%0Avar%20now%20%3D%20new%20Date%28%29%0Avar%20midnightToday%20%3D%20cal%2EstartOfDay%28now%29%0Avar%20dc%20%3D%20cal%2EdateComponentsFromDate%28midnightToday%29%0Adc%2Eday%20%3D%20dc%2Eday%20%2D%201%0Avar%20midnightYesterday%20%3D%20cal%2EdateFromDateComponents%28dc%29%0AflattenedTasks%2EforEach%28task%20%3D%3E%20%7B%0A%09var%20tdDate%20%3D%20task%2EdropDate%0A%09if%20%28tdDate%20%3E%3D%20midnightYesterday%20%26%26%20tdDate%20%3C%20midnightToday%29%7B%0A%09%09task%2Eactive%20%3D%20true%0A%09%7D%0A%7D%29%7Dcatch%28err%29%7Bconsole%2Elog%28err%29%7D
Un-Drop Tasks Dropped Yesterday
 

cal = Calendar.current now = new Date() midnightToday = cal.startOfDay(now) dc = cal.dateComponentsFromDate(midnightToday) dc.day = dc.day - 1 midnightYesterday = cal.dateFromDateComponents(dc) flattenedTasks.forEach(task => { tdDate = task.dropDate if (tdDate >= midnightYesterday && tdDate < midnightToday){ task.active = true } })

NOTE: Both of the previous script examples use properties and functions of the Calendar class to perform date calculations.

Set Floating Timezone Property

The following plug-in will set the value of the shouldUseFloatingTimeZone property for all existing tasks:

Set Time Zone Type for All Tasks
  

/*{ "type": "action", "targets": ["omnifocus"], "author": "Otto Automator", "identifier": "com.omni-automation.setTimeZoneTypeForAllTasks", "version": "1.2", "description": "Converts the time zone type for all tasks to the chosen type.", "label": "Set Time Zone Type for All Tasks", "shortLabel": "Set Time Zone Types", "paletteLabel": "Set Time Zone Types", "image": "timelapse" }*/ (() => { const action = new PlugIn.Action(async function(selection, sender){ timezoneTypesMenu = new Form.Field.Option( "timezoneType", null, [0,1], ["Current Time Zone", "Floating Time Zone"], 0 ) inputForm = new Form() inputForm.addField(timezoneTypesMenu) inputForm.validate = function(formObject){ return true } formPrompt = "Choose the time zone type for all tasks:" buttonTitle = "Continue" formObject = await inputForm.show(formPrompt,buttonTitle) typeIndex = formObject.values['timezoneType'] flattenedTasks.forEach((task) => { task.shouldUseFloatingTimeZone = [false, true][typeIndex] }) }); action.validate = function(selection, sender){ return true }; return action; })();

The TaskArray Class

An Array containing Task objects. Some of the properties of the Task class have values that are instances of the TaskArray class.

The TaskArray class offers a function for locating a task within the array by the name of the task.

Here is an example script that uses the flattenedTasks of the Database class to reveal the first occurence of a task by name in the database:

Reveal First Named Task


task = flattenedTasks.byName("Clean Gutters") if(task){ id = task.id.primaryKey URL.fromString("omnifocus:///task/" + id).open() }

To locate all tasks named with a specified name, use the JavaScript filter() function called on an instance of the TaskArray class, such as the flattenedTasks property of the Database class:

Locate Tasks with Specified Name


taskName = "Summary" matchedTasks = flattenedTasks.filter(task => { return task.name === taskName })

RELATED: In addition to the name property, database objects are sometimes identified by their unique identifier string. The Task class offers a global function for locating a task by identifier:

omnifocus://localhost/omnijs-run?script=try%7Bvar%20win%20%3D%20document%2Ewindows%5B0%5D%0Avar%20tasks%20%3D%20win%2Eselection%2Etasks%0Aif%20%28tasks%2Elength%20%3D%3D%3D%201%29%7B%0A%09var%20taskID%20%3D%20tasks%5B0%5D%2Eid%2EprimaryKey%0A%09console%2Elog%28taskID%29%0A%09new%20Alert%28%22Task%20ID%22%2CtaskID%29%2Eshow%28%29%0A%7D%7Dcatch%28err%29%7Bconsole%2Elog%28err%29%7D
ID of Selected Task
 

win = document.windows[0] tasks = win.selection.tasks if (tasks.length === 1){ taskID = tasks[0].id.primaryKey console.log(taskID) new Alert("Task ID",taskID).show() }
Reveal Task by ID


taskID = "dXL1Kdp4XCx" task = Task.byIdentifier(taskID) if(task){ urlStr = "omnifocus:///task/" + taskID URL.fromString(urlStr).open() }

The Task.Status Class

The values for the taskStatus property of the Task class:

omnifocus://localhost/omnijs-run?script=try%7Bvar%20tasks%20%3D%20flattenedTasks%2Efilter%28task%20%3D%3E%20%7B%0A%09return%20task%2EtaskStatus%20%3D%3D%3D%20Task%2EStatus%2EDueSoon%0A%7D%29%0Aif%20%28tasks%2Elength%20%20%3E%200%29%7B%0A%09tasks%2EforEach%28task%20%3D%3E%20%7Btask%2Eflagged%20%3D%20true%7D%29%0A%09document%2Ewindows%5B0%5D%2Eperspective%20%3D%20Perspective%2EBuiltIn%2EFlagged%0A%7D%7Dcatch%28err%29%7Bconsole%2Elog%28err%29%7D
Flag Tasks that are Due Soon
 

tasks = flattenedTasks.filter(task => { return task.taskStatus === Task.Status.DueSoon }) if (tasks.length > 0){ tasks.forEach(task => {task.flagged = true}) document.windows[0].perspective = Perspective.BuiltIn.Flagged }

Creating Tasks

To create an instance of the Task class, the standard JavaScript new item constructor is used:

omnifocus://localhost/omnijs-run?script=try%7Btask%20%3D%20new%20Task%28%22My%20Task%22%29%7Dcatch%28err%29%7Bconsole%2Elog%28err%29%7D
New Task at End of Inbox
 

task = new Task("My Task")
omnifocus://localhost/omnijs-run?script=try%7Btask%20%3D%20new%20Task%28%22My%20Task%22%2C%20inbox%2Ebeginning%29%7Dcatch%28err%29%7Bconsole%2Elog%28err%29%7D
New Task at Beginning of Inbox
 

task = new Task("My Task", inbox.beginning)

Once a task instance has been created, the value of its properties can be set:

omnifocus://localhost/omnijs-run?script=try%7Btask%20%3D%20new%20Task%28%22My%20Task%22%2C%20inbox%2Ebeginning%29%0Atask%2Enote%20%3D%20%22This%20is%20the%20note%20for%20the%20created%20task%2E%22%0Atask%2Eflagged%20%3D%20true%7Dcatch%28err%29%7Bconsole%2Elog%28err%29%7D
New Task with Properties
 

task = new Task("My Task", inbox.beginning) task.note = "This is the note for the created task." task.flagged = true

Here's an example script that creates and then displays a task in the application interface:

omnifocus://localhost/omnijs-run?script=try%7Btask%20%3D%20new%20Task%28%22My%20New%20Task%22%2C%20inbox%2Ebeginning%29%0AurlString%20%3D%20%22omnifocus%3A%2F%2F%2Ftask%2F%22%20%2B%20task%2Eid%2EprimaryKey%0AURL%2EfromString%28urlString%29%2Ecall%28%28%29%3D%3E%7B%7D%29%7Dcatch%28err%29%7Bconsole%2Elog%28err%29%7D
Make and Show New Task
 

task = new Task("My New Task", inbox.beginning) urlString = "omnifocus:///task/" + task.id.primaryKey URL.fromString(urlString).open()

(1) The JavaScript new item constructor takes the name for the new task as input, and optionally the insertion postion in the task’s parent container, as a second input parameter. The result is an object reference to the newly created task, which is stored in the variable: task

(2) Every element of the OmniFocus database, including tasks, projects, and folders, shares the id and primaryKey properties, which generate a unique identifier string for each element. This identifer can be appended to an OmniFocus URL that will cause the identified item to display in the app UI when the URL is called.

(3) The URL string is converted into a URL object using the fromString(…) method of the URL class, which is then called using the open( ) method of the same class.

 

Transport Text Parsing

Omni Automation support in OmniFocus offers a special class function for converting text instructions into new tasks. The syntax for the task creation instructions uses common characters and constructs that you can use as shorthand way of indicating tasks. When the text containing the instructions is parsed using the byParsingTransportText(…) function, new tasks are created.

In the following example, a new task is created in the specified existing project. The due date/time are assigned along with a specified existing tag.

Create Task(s) by Parsing Text


txt = `New Task!::Existing Project Title #12/12/20 8.30a $3h @existing-tag-name//This is the task note` newTasks = Task.byParsingTransportText(txt, true) taskID = newTasks[0].id.primaryKey URL.fromString("omnifocus:///task/" + taskID).open()
Transport Text Parsing

Here are the syntax rules for the task-creation shorthand:

As a “use-case” example, here’s a Drafts app action for parsing the content of the current Drafts document as OmniFocus Transport Text. Copy and paste this script into the Drafts app Action Editor.

Drafts app Action


(() => { // wrapping the action script in a self-invoking anonymous arrow function (() => {})(); // prevents possible conflicts between script actions that may use the same variable names // OmniFocus JavaScript Context // Omni Automation script as a function with text input function executeTransportTextString(transportString){ newTasks = Task.byParsingTransportText(transportString, null) taskID = newTasks[0].id.primaryKey URL.fromString("omnifocus:///task/" + taskID).open() }; // Host Application JavaScript Context (1Writer, Drafts, etc.) const transportString = editor.getText(); // create and execute an Omni Automation script URL const functionString = executeTransportTextString.toString(); const encodedFunction = encodeURIComponent(functionString); const inputString = JSON.stringify(transportString); const encodedInput = encodeURIComponent(inputString); const op = "%28"; const cp = "%29"; const scriptURL = `omnifocus://localhost/omnijs-run?script=${op}${encodedFunction}${cp}${op}argument${cp}&arg=${encodedInput}`; app.openURL(scriptURL); })();

The initial execution of the Drafts action will cause the display of the Omni Automation script security dialog. Select the checkbox option to run the script without re-approval and subsequent executions will be without a security dialog.

More information regarding the creation of Omni Automation script URLs can be found here.

Related Omni Automation Plug-In

DOWNLOAD a plug-in compatible with all Omni apps that parses the clipboard as Transport Text to generate new tasks in OmniFocus.

 

Task Instance Functions

Here are the functions that can be performed with an instance of the Task class:

Working with Tasks

The following script examples demonstrate how to use some of the functions of the Task class:

This first script demonstrates how to retrieve references to the currently selected tasks. The result will be an array of object references, or an empty array if no tasks are selected.

Get Selected Tasks


document.windows[0].selection.tasks

The value of the flattenedTasks property of the Database class is used to retrieve object references to all tasks in the database:

Retrieve References to All Tasks


flattenedTasks
Getting object references to all tasks in the Inbox:
Get All Tasks in Inbox


masterTaskArray = new Array() inbox.apply(task => masterTaskArray.push(task)) console.log(masterTaskArray)

The next script uses the apply(…) function to generate an array of object references to all of the tasks contained within the entire hierarchy of folders and projects:

Get All Tasks Contained in Projects in the Library


masterTaskArray = new Array() library.apply(function(item){ if (item instanceof Project && item.task.hasChildren){ masterTaskArray.push(item.task.children) } }) console.log(masterTaskArray)

The following script will focus any projects that contain tasks that are due soon:

omnifocus://localhost/omnijs-run?script=try%7Bvar%20parentProjects%20%3D%20new%20Array%28%29%0AflattenedProjects%2EforEach%28project%20%3D%3E%20%7B%0A%09if%20%28project%2EhasChildren%29%7B%0A%09%09project%2Echildren%2EforEach%28task%20%3D%3E%20%7B%0A%09%09%09if%20%28task%2EtaskStatus%20%3D%3D%3D%20Task%2EStatus%2EDueSoon%29%7B%0A%09%09%09%09if%20%28%21parentProjects%2Eincludes%28project%29%29%7B%0A%09%09%09%09%09parentProjects%2Epush%28project%29%0A%09%09%09%09%7D%09%09%09%0A%09%09%09%7D%0A%09%09%7D%29%0A%09%7D%0A%7D%29%0Aif%20%28parentProjects%2Elength%20%3E%200%29%7B%0A%09document%2Ewindows%5B0%5D%2Eperspective%20%3D%20Perspective%2EBuiltIn%2EProjects%0A%09document%2Ewindows%5B0%5D%2Efocus%20%3D%20parentProjects%0A%7D%7Dcatch%28err%29%7Bconsole%2Elog%28err%29%7D
Focus Projects with Tasks Due Soon
 

parentProjects = new Array() flattenedProjects.forEach(project => { if (project.hasChildren){ project.children.forEach(task => { if (task.taskStatus === Task.Status.DueSoon){ if (!parentProjects.includes(project)){ parentProjects.push(project) } } }) } }) if (parentProjects.length > 0){ document.windows[0].perspective = Perspective.BuiltIn.Projects document.windows[0].focus = parentProjects }

Using the added property of the Database Object class to sort all tasks by the date they were added to the database:

Sort Tasks by Creation Date


tasks = flattenedTasks tasks.sort((a, b) => { var x = a.added; var y = b.added; if (x < y) {return -1;} if (x > y) {return 1;} return 0; }) tasks.map(task => {return task.name})

Marking the selected tasks complete:

Mark Selected Tasks Complete


(async () => { try { items = document.windows[0].selection.tasks if(items.length === 0){ throw { name: "Selection Issue", message: "Please select one or more tasks." } } items.forEach(item => {item.markComplete()}) } catch(err){ if(!err.message.includes("cancelled")){ await new Alert(err.name, err.message).show() } throw `${err.name}\n${err.message}` } })();

Assigning Tags to Tasks

The addTag(…) and addTags(…) functions of the Task class are used to assign tags to tasks. These functions require object references to the tags to add as the function input. The following script uses the flattenedTags property of the Database class to generate a reference to an existing tag, creating a new tag if needed:

Get Tag Reference by Name


tag = flattenedTags.byName("Conifer") || new Tag("Conifer")

The previous technique for generating a tag reference is used to apply a specified tag to the selected tasks:

Apply Tag to Selected Tasks


tagName = "Redwood" tag = flattenedTags.byName(tagName) || new Tag(tagName) tasks = document.windows[0].selection.tasks tasks.forEach(task => {task.addTag(tag)})

Using similar techniques and the addTags(…) function to apply an array of tags to each of the selected tasks:

Apply Tags to Selected Tasks


tagTitles = ["Northeast","Atlantic Seaboard","New England","Rhode Island"] tagRefs = new Array() tagTitles.forEach(title => { tagObj = flattenedTags.byName(title) || new Tag(title) tagRefs.push(tagObj) }) tasks = document.windows[0].selection.tasks tasks.forEach(task => {task.addTags(tagRefs)})

Plug-In: Open Link in Note

This Omni Automaton plug-in will scan the note text of the selected project or task, and if it locates an URL in the text, will open the found URL.

Open Project|Action Note URL
  

/*{ "type": "action", "targets": ["omnifocus"], "author": "Otto Automator", "identifier": "com.omni-automation.call-note-url", "version": "1.6", "description": "This action will open the URL string that is the value of the note of the selected action.", "label": "Open Note URL", "shortLabel": "Open Note URL", "paletteLabel": "Open Note URL", "image": "link.circle" }*/ (() => { const action = new PlugIn.Action(function(selection, sender){ note = (selection.projects.length === 1 ? selection.projects[0].task.note : selection.tasks[0].note) if (note && note.includes("://")) { urlStr = note.match(/[^<\s][^\s]+\/\/[^\s>]+/)[0] url = URL.fromString(urlStr) if(url){ url.open() } else { console.error("ERROR: \"" + urlStr + "\" is not a valid URL.") } } }); action.validate = function(selection, sender){ return ( selection.projects.length === 1 || selection.tasks.length === 1 ) }; return action; })();

Move Tasks

Here are two Omni Automation Plug-Ins for moving selected tasks into either a new task group or a new project.

Move Selected Tasks into New Project
  

/*{ "type": "action", "targets": ["omnifocus"], "author": "Otto Automator", "identifier": "com.omni-automation.of.move-selected-tasks-into-project", "version": "1.3", "description": "Move the selected tasks into a new top-level project.", "label": "Move Selected Tasks into New Project", "shortLabel": "Move Tasks", "paletteLabel": "Move Tasks", "image": "square.and.arrow.down.fill" }*/ (() => { const action = new PlugIn.Action(async function(selection, sender){ // CONSTRUCT THE FORM inputForm = new Form() // CREATE FORM ELEMENT: TEXT INPUT textField = new Form.Field.String("projectName", "Project Name", null) // CREATE FORM ELEMENT: OPTION MENU popupMenu = new Form.Field.Option( "projectType", "Project Type", [0, 1, 2], ["Parallel","Sequential","Single Actions"], 0 ) // ADD THE ELEMENTS TO THE FORM inputForm.addField(textField) inputForm.addField(popupMenu) // VALIDATE FORM CONTENT inputForm.validate = function(formObject){ // EXTRACT VALUES FROM THE FORM’S VALUES OBJECT textValue = formObject.values['projectName'] return ((textValue) ? true:false) } // DIALOG PROMPT AND OK BUTTON TITLE formPrompt = "Enter the name for the new top-level project and select its project type:" buttonTitle = "Continue" // DISPLAY THE FORM DIALOG formObject = await inputForm.show(formPrompt, buttonTitle) // PERFORM PROCESSES USING FORM DATA textValue = formObject.values['projectName'] menuItemIndex = formObject.values['projectType'] // CREATE PROJECT AND MOVE TASKS project = new Project(textValue) moveTasks(selection.tasks, project) // SET THE PROJECT TYPE if (menuItemIndex === 1){ project.task.sequential = true } else if (menuItemIndex === 2){ project.containsSingletonActions = true } // SHOW THE PROJECT projID = project.id.primaryKey urlStr = "omnifocus:///task/" + projID URL.fromString(urlStr).open() }); action.validate = function(selection, sender){ return (selection.tasks.length > 0) }; return action; })();
Move Selected Tasks into New Action Group
  

/*{ "type": "action", "targets": ["omnifocus"], "author": "Otto Automator", "identifier": "com.omni-automation.of.move-selected-tasks-into-new-action", "version": "1.4", "description": "Move the selected tasks into a new top-level action group.", "label": "Move Selected Tasks into New Action Group", "shortLabel": "Move Tasks", "paletteLabel": "Move Tasks", "image": "archivebox.circle" }*/ (() => { const action = new PlugIn.Action(async function(selection, sender){ // CONSTRUCT THE FORM inputForm = new Form() // CREATE FORM ELEMENTS: TEXT INPUT textField = new Form.Field.String("groupName", null, null) // CREATE FORM ELEMENT: OPTION MENU popupMenu = new Form.Field.Option( "actionType", "Action Type", [0, 1], ["Parallel","Sequential"], 0 ) // ADD THE ELEMENTS TO THE FORM inputForm.addField(textField) inputForm.addField(popupMenu) // VALIDATE FORM CONTENT inputForm.validate = function(formObject){ // EXTRACT VALUES FROM THE FORM’S VALUES OBJECT textValue = formObject.values['groupName'] return ((textValue) ? true:false) } // DIALOG PROMPT AND OK BUTTON TITLE formPrompt = "Provide name and type for new top-level action group:" buttonTitle = "Continue" // DISPLAY THE FORM DIALOG formObject = await inputForm.show(formPrompt, buttonTitle) // PERFORM PROCESSES USING FORM DATA textValue = formObject.values['groupName'] menuItemIndex = formObject.values['actionType'] taskGroup = new Task(textValue) moveTasks(selection.tasks, taskGroup) // SET THE PROJECT TYPE if (menuItemIndex === 1){ taskGroup.sequential = true } // SHOW THE ACTION taskID = taskGroup.id.primaryKey urlStr = "omnifocus:///task/" + taskID URL.fromString(urlStr).open() }); action.validate = function(selection, sender){ return (selection.tasks.length > 0) }; return action; })();

Display Host Project

If you have a project task selected, this plug-in will feature the containing project in the OmniFocus window:

Display Host Project
  

/*{ "type": "action", "targets": ["omnifocus"], "author": "Otto Automator", "identifier": "com.omni-automation.of.display-host-project", "version": "1.7", "description": "This action will display the host project of the selected task.", "label": "Display Host Project", "shortLabel": "Display Project", "paletteLabel": "Display Project", "image": "archivebox" }*/ (() => { const action = new PlugIn.Action(async function(selection, sender){ project = selection.tasks[0].containingProject projID = project.id.primaryKey urlStr = "omnifocus:///task/" + projID URL.fromString(urlStr).open() }); action.validate = function(selection, sender){ return ( selection.tasks.length === 1 && selection.tasks[0].containingProject ) }; return action; })();

Delete All Tasks Tagged with Specific Tag

Here’s an Omni Automation action that will delete all of the tasks that are tagged with the tag specified by the user.

Delete All Tasks Tagged with Tag
  

/*{ "type": "action", "targets": ["omnifocus"], "author": "Otto Automator", "identifier": "com.omni-automation.com.of.delete-tasks-with-tag", "version": "1.1", "description": "This action will delete all tasks that have been tagged with the specified tag.", "label": "Delete All Tasks with Tag", "shortLabel": "Delete Tasks with Tag", "paletteLabel": "Delete Tasks with Tag", "image": "tag.slash" }*/ (() => { const action = new PlugIn.Action(async function(selection, sender){ try { tagNames = new Array() tags.apply(tag => tagNames.push(tag.name)) if (tagNames.length === 0){throw Error("No tags in database")} textInputField = new Form.Field.String( "textInput", null, null ) inputForm = new Form() inputForm.addField(textInputField) inputForm.validate = function(formObject){ var inputText = formObject.values['textInput'] var textStatus = ((!inputText)?false:true) return (textStatus && tagNames.includes(inputText)) ? true : false } formPrompt = "Enter the title of the tag whose tasks will be deleted:" buttonTitle = "Continue" formObject = await inputForm.show(formPrompt,buttonTitle) tagTitle = formObject.values['textInput'] targetTag = null tags.apply(function(tag){ if(tag.name == tagTitle){ targetTag = tag return ApplyResult.Stop } }) targetTasks = targetTag.tasks targetTasks.forEach(task => { deleteObject(task) }) msg = String(targetTasks.length) + " task(s) have been deleted." new Alert("STATUS", msg).show() } catch (err){ new Alert('SCRIPT ERROR', err.message).show() } }); action.validate = function(selection, sender){ return true }; return action; })();

Save Task as Calendar File

This action will save the data of the selected task to a standard iCalendar file.

iCal File for Task
  

/*{ "type": "action", "targets": ["omnifocus"], "author": "Otto Automator", "identifier": "com.omni-automation.of.ics-file-for-task", "version": "1.4", "description": "This action will create an iCal (ics) file in the OmniFocus documents folder, matching the parameters of the currently selected task. On macOS, the file will be automatically opened causing the Calendar application to present a new event dialog.", "label": "iCal File for Task", "shortLabel": "iCal File", "image": "calendar.badge.plus" }*/ (() => { function uuidv4() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); }); } function dateToCalDateStamp(date){ var dateStamp = date.toISOString().split("-").join("").split(":").join("").replace(".","") dateStamp = dateStamp.substring(0, dateStamp.length - 4) + "Z" return dateStamp } const action = new PlugIn.Action(async function(selection, sender){ try { task = selection.tasks[0] taskID = task.id.primaryKey taskURL = "omnifocus:///task/" + taskID taskTitle = task.name taskNote = task.note if (!taskNote){ taskNote = "" } else { // Replace CR+LF and LF newlines with \n for iCal format taskNote = taskNote.replace(/\n/g, '\\n'); } taskDueDateStamp = dateToCalDateStamp(task.dueDate) taskDuration = task.estimatedMinutes if (!taskDuration){taskDuration = 60} taskEndDate = task.dueDate taskEndDate = new Date( taskEndDate.setMinutes(taskEndDate.getMinutes() + taskDuration) ) taskEndDateStamp = dateToCalDateStamp(taskEndDate) dateStamp = dateToCalDateStamp(new Date()) uid = uuidv4() calEventString = `BEGIN:VCALENDAR VERSION:2.0 PRODID:-//omni-automation.com CALSCALE:GREGORIAN METHOD:PUBLISH BEGIN:VEVENT SUMMARY:${taskTitle} UID:${uid} SEQUENCE:0 STATUS:CONFIRMED TRANSP:TRANSPARENT RRULE: DTSTART:${taskDueDateStamp} DTEND:${taskEndDateStamp} DTSTAMP:${dateStamp} CATEGORIES: LOCATION: GEO: DESCRIPTION:${taskNote} URL:${taskURL} END:VEVENT END:VCALENDAR` console.log(calEventString) filename = 'event.ics' textData = Data.fromString(calEventString) wrapper = FileWrapper.withContents(filename, textData) folderURL = URL.documentsDirectory fileURL = folderURL.appendingPathComponent(filename) wrapper.write( fileURL, [FileWrapper.WritingOptions.Atomic], null ) if (Device.current.mac){ fileURL.open() } } catch(err){ if(!err.causedByUserCancelling){ new Alert(err.name, err.message).show() } } }); action.validate = function(selection, sender){ return (selection.tasks.length === 1 && selection.tasks[0].dueDate != null) }; return action; })();