The Window class contains the DocumentWindow subclass that displays the controls and views for accessing and altering the data in the OmniFocus backing database.

The scripting implementation for the Window class contains no properties, and one function.

Close All But Front Window

if (document.windows.length > 1){ var winCount = document.windows.length for (var i = winCount - 1; i >= 1; i--) { document.windows[i].close() } }

DocumentWindow Instance Properties

Here are the properties of the DocumentWindow class:

The “name” of an OmniFocus window is the name of the perspective it currently displays. Here’s a script that gets the names of the open OmniFocus windows:

Names of Windows

winNames = document.windows.map(win => win.perspective.name)

A script that sets the value of the focus property:

Setting Window Focus

project1 = projectNamed("My Top-Level Project") project2 = projectNamed("Single-Action Project") document.windows[0].focus = [project1, project2]

A script that sets the value of the perspective property:

Get | Set Perspective

// get the current perspective object document.windows[0].perspective //--> [object Perspective.BuiltIn: Projects] // set the perspective document.windows[0].perspective = Perspective.BuiltIn.Inbox

A script that sets the values of the perspective and focus properties:

Focus Dropped Projects

var dropped = new Array() library.apply(item => { if (item instanceof Project && item.status === Project.Status.Dropped){ dropped.push(item) } }) if(dropped.length > 0){ document.windows[0].perspective = Perspective.BuiltIn.Projects document.windows[0].focus = dropped }

And a version of the previous script using the JavaScript filter(…) function with the flattenedProjects property of the Database class:

Focus Dropped Projects

var dropped = flattenedProjects.filter(proj => { return proj.status === Project.Status.Dropped }) if(dropped.length > 0){ document.windows[0].perspective = Perspective.BuiltIn.Projects document.windows[0].focus = dropped }

NOTE: the value of the content and sidebar properties of the Window class are ContentTree and SidebarTree types that inherit from the Tree class, which is the same class that is used to organize and control the display of items in OmniOutliner. Currently these node trees are implemented only on macOS, and are not functional on iOS or iPadOS.

Select Currently Displayed Tasks

var windowContent = document.windows[0].content var nodes = new Array() windowContent.rootNode.apply(item => { if (item.object instanceof Task) { nodes.push(item) } }) if(nodes.length > 0){ windowContent.select(nodes) }

Here's a plug-in based upon the previous script that will select all of the tasks and/or projects in the current content view. The plug-in includes an action form for displaying a dialog from which the user can choose which type of object to select:

Select All Items in Content View

/*{ "type": "action", "targets": ["omnifocus"], "author": "Otto Automator", "identifier": "com.omni-automation.of.select-all-visible-items", "version": "1.0", "description": "This action will select all of the tasks and/or projects in the current content view. (macOS only)", "label": "Select Items in View", "shortLabel": "Select Items" }*/ (() => { var action = new PlugIn.Action(function(selection, sender){ // action code // selection options: tasks, projects, folders, tags var tasksCheckbox = new Form.Field.Checkbox( "shouldSelectTasks", "Tasks", false ) var projectsCheckbox = new Form.Field.Checkbox( "shouldSelectProjects", "Projects", false ) var inputForm = new Form() inputForm.addField(tasksCheckbox) inputForm.addField(projectsCheckbox) var formPromise = inputForm.show("Select in content view:","Continue") inputForm.validate = function(formObject){ var shouldSelectTasks = formObject.values['shouldSelectTasks'] var shouldSelectProjects = formObject.values['shouldSelectProjects'] return ((shouldSelectTasks || shouldSelectProjects) ? true:false) } formPromise.then(function(formObject){ var shouldSelectTasks = formObject.values['shouldSelectTasks'] var shouldSelectProjects = formObject.values['shouldSelectProjects'] var items = new Array() document.windows[0].content.rootNode.apply((item) => { if (shouldSelectTasks && item.object instanceof Task) { items.push(item); } if (shouldSelectProjects && item.object instanceof Project) { items.push(item); } }) if(items != []){ document.windows[0].content.select(items) } }) }); action.validate = function(selection, sender){ // validation code // selection options: tasks, projects, folders, tags return (Device.current.mac) }; return action; })();

Instance Functions

Here are the instance functions for the Window class:

IMPORTANT: Since the use these functions require a specific perspective be displayed, the example scripts may occasionally incorporate the use of a Timer function to allow the window time to change views.

The following script uses the flattenedProjects property of the Database class and the byName() and selectObjects() function to select the first project whose name matches the specified name:

Select 1st Project with Specified Name

var targetName = "Project A" var targetProject = flattenedProjects.byName(targetName) if(targetProject){ document.windows[0].perspective = Perspective.BuiltIn.Projects document.windows[0].selectObjects([targetProject]) }

NOTE: The following forecast example scripts use properties and functions of the shared Calendar and DateComponents classes to calculate dates.

Here’s a script that will select the forecast day seven (7) days form today:

Select Forecast for 7th Day from Today

document.windows[0].perspective = Perspective.BuiltIn.Forecast var now = new Date() var cal = Calendar.current var today = cal.startOfDay(now) var dc = new DateComponents() dc.day = 7 var targetDate = cal.dateByAddingDateComponents(today,dc) var fday = document.windows[0].forecastDayForDate(targetDate) document.windows[0].selectForecastDays([fday])

The following example script demonstrates how to select a range of forecast days (macOS only):

Select Range of Forecast Days

document.windows[0].perspective = Perspective.BuiltIn.Forecast var now = new Date() var cal = Calendar.current var today = cal.startOfDay(now) var dc = new DateComponents() var fdays = new Array() var fday, targetDate, i for (i = 0; i < 7; i++) { dc.day = i + 1 targetDate = cal.dateByAddingDateComponents(today,dc) fday = document.windows[0].forecastDayForDate(targetDate) fdays.push(fday) } document.windows[0].selectForecastDays(fdays)

Document Selection

A document’s Selection object belongs to the Window class, which in turn, belongs to the parent implied document. The Selection class includes properties whose values are arrays of references to the specified object types selected in the window: projects, folders, tags, tasks, and a special property for returning all selected database objects (non-interface elements): databaseObjects

Document > Window > Selection

Selection Properties

document.windows[0].selection.database document.windows[0].selection.databaseObjects document.windows[0].selection.folders document.windows[0].selection.projects document.windows[0].selection.tags document.windows[0].selection.tasks document.windows[0].selection.window document.windows[0].selection.allObjects

For example, here’s a simple script for getting the titles of the selected tasks:

Get Names of Selected Tasks

var selectedTasks = document.windows[0].selection.tasks var taskTitles = selectedTasks.map(task => task.name) console.log(taskTitles)

This script will move the selected projects into new top-level folder:

Move Selected Projects into New Folder

var items = document.windows[0].selection.projects if(items.length > 0){ moveSections(items, new Folder("Project Group")) }

The DatabaseDocument Class

The DatabaseDocument class is used to create new windows or tabs containing views of the database content.

New Window showing Projects Perspective

var winPromise = document.newWindow() winPromise.then(win => { win.perspective = Perspective.BuiltIn.Projects }) winPromise.catch(err => { console.error(err.message) })
Add Forecast Tab to Front Window (macOS)

if(app.platformName === 'macOS'){ var winPromise = document.newTabOnWindow(document.windows[0]) winPromise.then(win => { win.perspective = Perspective.BuiltIn.Forecast }) winPromise.catch(err => { console.error(err.message) }) }

Append Tags of Chosen Task to Selected Tasks

The following Omni Automaton plug-in uses the document selection, the addTags(…) function of the Task class, and interactive Action Forms, to copy the tags of a chosen task to the other tasks selected in the OmniFocus window.

To use, select both the tasks to receive the tags, and the task containing the set of tags to be copied, and run the action. The plug-in offers an option to clear any existing tags from the receiving tasks prior to appending the tags of the source task.

Append Tags of Chosen Task to Selected Tasks

/*{ "type": "action", "targets": ["omnifocus"], "author": "Otto Automator", "identifier": "com.omni-automation.of.append-tags-from-selected-task", "version": "2.0", "description": "Append tags of the chosen task to the other selected tasks.", "label": "Append Tags of Chosen Task to Tasks", "shortLabel": "Copy Tags" }*/ (() => { var action = new PlugIn.Action(function(selection, sender){ var tasks = document.windows[0].selection.tasks if (tasks.length > 1){ // sort the task objects by name tasks.sort((a, b) => { var x = a.name.toLowerCase(); var y = b.name.toLowerCase(); if (x < y) {return -1;} if (x > y) {return 1;} return 0; }) } else { throw new Error("Select two or more tasks.") } // generate a list of task names var taskNames = tasks.map(task => {return task.name}) // generate a list of matching indexes var menuIndexes = new Array() taskNames.forEach((item,index) => {menuIndexes.push(index)}) var multiOptionMenu = new Form.Field.MultipleOptions( "menuKey", "Select source task", menuIndexes, taskNames, [] ) var checkboxSwitch = new Form.Field.Checkbox( "clearTags", "Clear existing tags from selected tasks", false ) var inputForm = new Form() inputForm.addField(checkboxSwitch) inputForm.addField(multiOptionMenu) var formPrompt = "Append tags of the chosen task to the other selected tasks:" var buttonTitle = "Continue" var formPromise = inputForm.show(formPrompt,buttonTitle) inputForm.validate = function(formObject){ var indexes = formObject.values["menuKey"] // ensure one item is selected return (indexes.length === 1)?true:false } formPromise.then(function(formObject){ var index = formObject.values["menuKey"] var clearTags = formObject.values["clearTags"] var sourceTask = tasks[index] var sourceTags = sourceTask.tags tasks.forEach(task => { if(clearTags){task.clearTags()} task.addTags(sourceTags) }) }) formPromise.catch(function(err){ console.error("form cancelled", err.message) }) }); action.validate = function(selection, sender){ return (selection.tasks.length > 1) }; return action; })();

Displaying (selecting) an Item in the Window

While the focus property of the DocumentWindow class can be used to display specific folders and projects, currently the Omni Automation implementation in OmniFocus does not offer a script function for setting the contents of the Selection class to a specific task. However, you can incorporate the built-in URL support of OmniFocus with scripts to create and execute URLs that will cause specified items to be displayed in the document window.

To create a URL for displaying (selecting) an OmniFocus object, the primaryKey property of the ObjectIdentifer class is appended to the standard OmniFocus URL task protocol, as in the following Omni Automation action that displays the parent project of a selected task:

Display Parent Project of Selected Task

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

(01-10)  The Action metadata.

(11-31)  The main function containing the action code.

(21-28)  The action validation routine will enable the action in the Automation menu when a single task, contained in a project, is selected.

(12-22)  The function for creating the action, which is passed the selection object by default.

(15)  Use the containingProject property of the Task class to get a reference to the parent project. If the selected task is not included in a project, no value (undefined) will be returned.

(16)  The value of the primaryKey property is a unique identifier string.

(17)  Append the identifier string to URL string targeting the OmniFocus application.

(18)  Use the fromString(…) method of the URL class to convert the string into a URL object, and then execute the url by appending the open() function to the result.