×

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.

NOTE: Beginning with OmniFocus v4.2:

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

omnifocus://localhost/omnijs-run?script=try%7Bif%20%28document%2Ewindows%2Elength%20%3E%201%29%7B%0A%09document%2Ewindows%2EforEach%28%28win%2Cindex%29%20%3D%3E%20%7B%0A%09%09if%20%28index%20%21%3D%200%29%7B%0A%09%09%09console%2Elog%28%22close%20%22%20%2B%20index%29%0A%09%09%09win%2Eclose%28%29%0A%09%09%7D%0A%09%7D%29%0A%7D%7Dcatch%28err%29%7Bconsole%2Elog%28err%29%7D
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:

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:

omnifocus://localhost/omnijs-run?script=try%7Bproject1%20%3D%20projectNamed%28%22My%20Top%2DLevel%20Project%22%29%0Aproject2%20%3D%20projectNamed%28%22Single%2DAction%20Project%22%29%20%0Adocument%2Ewindows%5B0%5D%2Efocus%20%3D%20%5Bproject1%2C%20project2%5D%7Dcatch%28err%29%7Bconsole%2Elog%28err%29%7D
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 will 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. As of OmniFocus 4, these node trees are implemented macOS, as well as iOS and iPadOS.

omnifocus://localhost/omnijs-run?script=var%20windowContent%20%3D%20document%2Ewindows%5B0%5D%2Econtent%0Avar%20nodes%20%3D%20new%20Array%28%29%0AwindowContent%2ErootNode%2Eapply%28item%20%3D%3E%20%7B%0A%09if%20%28item%2Eobject%20instanceof%20Task%29%20%7B%0A%09%09nodes%2Epush%28item%29%0A%09%7D%0A%7D%29%0Aif%28nodes%2Elength%20%3E%200%29%7B%0A%09windowContent%2Eselect%28nodes%29%0A%7D
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:

content-selection-choose-sheet
Select All Items in Content View
  

/*{ "type": "action", "targets": ["omnifocus"], "author": "Otto Automator", "identifier": "com.omni-automation.of.select-all-visible-items", "version": "1.1", "description": "This action will select all of the tasks and or projects in the current content view.", "label": "Select Items in View", "shortLabel": "Select Items", "paletteLabel": "Select Items", "image": "square.stack.3d.up" }*/ (() => { const action = new PlugIn.Action(async function(selection, sender){ try { tasksCheckbox = new Form.Field.Checkbox( "shouldSelectTasks", "Tasks", false ) projectsCheckbox = new Form.Field.Checkbox( "shouldSelectProjects", "Projects", false ) inputForm = new Form() inputForm.addField(tasksCheckbox) inputForm.addField(projectsCheckbox) inputForm.validate = function(formObject){ shouldSelectTasks = formObject.values['shouldSelectTasks'] shouldSelectProjects = formObject.values['shouldSelectProjects'] return ((shouldSelectTasks || shouldSelectProjects) ? true:false) } formObject = await inputForm.show("Select in content view:","Continue") shouldSelectTasks = formObject.values['shouldSelectTasks'] shouldSelectProjects = formObject.values['shouldSelectProjects'] 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.length > 0){ document.windows[0].content.select(items) } } catch(err){ if (!err.causedByUserCancelling){ new Alert(err.name, err.message).show() } } }); action.validate = function(selection, sender){ return true }; 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:

omnifocus://localhost/omnijs-run?script=try%7Bdocument%2Ewindows%5B0%5D%2Eperspective%20%3D%20Perspective%2EBuiltIn%2EForecast%0ATimer%2Eonce%281%2Cfunction%28timer%29%7B%0A%09var%20now%20%3D%20new%20Date%28%29%0A%09var%20today%20%3D%20Calendar%2Ecurrent%2EstartOfDay%28now%29%0A%09var%20dc%20%3D%20new%20DateComponents%28%29%0A%09dc%2Eday%20%3D%207%0A%09var%20targetDate%20%3D%20Calendar%2Ecurrent%2EdateByAddingDateComponents%28today%2Cdc%29%0A%09var%20fday%20%3D%20document%2Ewindows%5B0%5D%2EforecastDayForDate%28targetDate%29%0A%09document%2Ewindows%5B0%5D%2EselectForecastDays%28%5Bfday%5D%29%0A%7D%29%7Dcatch%28err%29%7Bconsole%2Elog%28err%29%7D
Select Forecast for 7th Day from Today
 

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

The following example script demonstrates how to select a range of forecast days:

omnifocus://localhost/omnijs-run?script=try%7Bdocument%2Ewindows%5B0%5D%2Eperspective%20%3D%20Perspective%2EBuiltIn%2EForecast%0ATimer%2Eonce%281%2Cfunction%28timer%29%7B%09%09%0A%09var%20now%20%3D%20new%20Date%28%29%0A%09var%20today%20%3D%20Calendar%2Ecurrent%2EstartOfDay%28now%29%0A%09var%20dc%20%3D%20new%20DateComponents%28%29%0A%09var%20fdays%20%3D%20new%20Array%28%29%0A%09var%20fday%2C%20targetDate%2C%20i%0A%09for%20%28i%20%3D%200%3B%20i%20%3C%207%3B%20i%2B%2B%29%20%7B%20%0A%09%09dc%2Eday%20%3D%20i%20%2B%201%0A%09%09targetDate%20%3D%20Calendar%2Ecurrent%2EdateByAddingDateComponents%28today%2Cdc%29%0A%09%09fday%20%3D%20document%2Ewindows%5B0%5D%2EforecastDayForDate%28targetDate%29%0A%09%09fdays%2Epush%28fday%29%0A%09%7D%0A%09document%2Ewindows%5B0%5D%2EselectForecastDays%28fdays%29%0A%7D%29%7Dcatch%28err%29%7Bconsole%2Elog%28err%29%7D
Select Range of Forecast Days
 

document.windows[0].perspective = Perspective.BuiltIn.Forecast now = new Date() cal = Calendar.current today = cal.startOfDay(now) dc = new DateComponents() 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:

omnifocus://localhost/omnijs-run?script=try%7BselectedTasks%20%3D%20document%2Ewindows%5B0%5D%2Eselection%2Etasks%0AtaskTitles%20%3D%20selectedTasks%2Emap%28task%20%3D%3E%20task%2Ename%29%0Aconsole%2Elog%28taskTitles%29%7Dcatch%28err%29%7Bconsole%2Elog%28err%29%7D
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:

omnifocus://localhost/omnijs-run?script=try%7Bitems%20%3D%20document%2Ewindows%5B0%5D%2Eselection%2Eprojects%0Aif%28items%2Elength%20%3E%200%29%7BmoveSections%28items%2C%20new%20Folder%28%22Project%20Group%22%29%29%7D%7Dcatch%28err%29%7Bconsole%2Elog%28err%29%7D
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.

omnifocus://localhost/omnijs-run?script=try%7Bvar%20windowPromise%20%3D%20document%2EnewWindow%28%29%0AwindowPromise%2Ethen%28function%28win%29%7B%0A%09win%2Eperspective%20%3D%20Perspective%2EBuiltIn%2EProjects%0A%7D%29%0AwindowPromise%2Ecatch%28function%28error%29%7B%0A%09console%2Eerror%28error%2Emessage%29%0A%7D%29%7Dcatch%28err%29%7Bconsole%2Elog%28err%29%7D
New Window showing Projects Perspective
 

var winPromise = document.newWindow() winPromise.then(win => { win.perspective = Perspective.BuiltIn.Projects }) winPromise.catch(err => { console.error(err.message) })
omnifocus://localhost/omnijs-run?script=try%7Bvar%20windowPromise%20%3D%20document%2EnewTabOnWindow%28document%2Ewindows%5B0%5D%29%0AwindowPromise%2Ethen%28function%28win%29%7B%0A%09win%2Eperspective%20%3D%20Perspective%2EBuiltIn%2EForecast%0A%7D%29%0AwindowPromise%2Ecatch%28function%28error%29%7B%0A%09console%2Eerror%28error%2Emessage%29%0A%7D%29%7Dcatch%28err%29%7Bconsole%2Elog%28err%29%7D
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.1", "description": "Append tags of the chosen task to the other selected tasks.", "label": "Append Tags of Chosen Task to Tasks", "shortLabel": "Copy Tags", "paletteLabel": "Copy Tags", "image": "tag" }*/ (() => { const action = new PlugIn.Action(async function(selection, sender){ tasks = 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 taskNames = tasks.map(task => {return task.name}) // generate a list of matching indexes menuIndexes = taskNames.map((item,index) => index) multiOptionMenu = new Form.Field.MultipleOptions( "menuKey", "Select source task", menuIndexes, taskNames, [] ) checkboxSwitch = new Form.Field.Checkbox( "clearTags", "Clear existing tags from selected tasks", false ) inputForm = new Form() inputForm.addField(checkboxSwitch) inputForm.addField(multiOptionMenu) inputForm.validate = function(formObject){ var indexes = formObject.values["menuKey"] // ensure one item is selected return (indexes.length === 1)?true:false } formPrompt = "Append tags of the chosen task to the other selected tasks:" buttonTitle = "Continue" formObject = await inputForm.show(formPrompt,buttonTitle) index = formObject.values["menuKey"] clearTags = formObject.values["clearTags"] sourceTask = tasks[index] sourceTags = sourceTask.tags tasks.forEach(task => { if(clearTags){task.clearTags()} task.addTags(sourceTags) }) }); 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.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; })();

(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.

Adding a New Tab Showing Specific Project

How to create and populate a new tab:

New Tab with Project


(async () => { try { await document.newTabOnWindow(document.windows[0]) document.windows[1].perspective = Perspective.BuiltIn.Projects project = flattenedProjects.byName("4-Step Success") document.windows[1].focus = [project] } catch(err){ new Alert(err.name, err.message).show() } })();