Window
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() • Close the document window: document.windows[0].close()
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:
content (ContentTree or null r/o) • (macOS) The tree of nodes representing the content area of the window.
focus (Array of Project or Folder or null) • The Folders and Projects that the window is focusing on, limiting the sidebar to show only these items. To unfocus, provide an empty array as the value: [ ]
inpsectorVisible (Boolean) • (v4.+) Whether the inspector is currently visible in the window. On iOS, showing this pane may implicitly hide other panes and may be only transiently visible, depending on the available space.
isTab (Boolean r/o) • (macOS) Whether or not this window is a tab. This is not available on iOS or iPadOS.
perspective (Perspective.BuiltIn or Perspective.Custom or null) • The perspective displayed in the window.
selection (Selection r/o) • The window selection object (see next section for details)
sidebar (SidebarTree or null r/o) • (macOS) The tree of nodes representing the sidebar of the window.
sidebarVisible (Boolean) • (v4.+) Whether the sidebar is currently visible in the window. On iOS, showing this pane may implicitly hide other panes and may be only transiently visible, depending on the available space.
tabGroupWindows (Array of DocumentWindow r/o) • (macOS) The array of sibling Window objects that are in tabs alongside this Window. If isTab is false, then this will return an array that solely contains this Window. This is not available on iOS or iPadOS.
Window Panel Visibility
function showWindowPanels(shouldShow){
window = document.windows[0]
window.sidebarVisible = shouldShow
window.inspectorVisible = shouldShow
}
showWindowPanels(false)
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
}
A script that wil focus only projects that have been tagged with the indicated tags:
Focus Tagged Projects
tag1 = flattenedTags.byName("Weekend") || new Tag("Weekend")
tag2 = flattenedTags.byName("Hiking") || new Tag("Hiking")
matched = flattenedProjects.filter(project => {
tgs = project.tags
return tgs.includes(tag1) && tgs.includes(tag2)
})
if(matched.length > 0){
document.windows[0].focus = matched
}
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:
selectObjects(objects:Array of DatabaseObject) → ( ) • Clears the current selection and then selects the given objects, if present in the current perspective of this window. On iOS, if objects contains more than one object, this will put the outline view into edit mode to accomodate multiple selection.
forecastDayForDate(date:Date) → (ForecastDay) • Returns a ForecastDay object that encompasses date. This will throw an error if Forecast is not the current perspective in this window.
selectForecastDays(days:Array of ForecastDay) → ( ) • Selects the days in the Forecast picker represented by days. On iOS, only the first day is selected, and the rest are ignored. This will throw an error if Forecast is not the current perspective in this window.
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.
newWindow() → (Promise) • Returns a Promise that will yield either a newly created and displayed Window or an error. On macOS, this method respects the System Preference governing new window behavior (tab vs. window). That preference is accessible at System Preferences > Dock > Prefer tabs when opening documents.
newTabOnWindow(window:DocumentWindow) → (Promise) • Returns a Promise that will yield either a new tab adjacent to window or an error. This is not available on iOS.
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.