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.

if (document.windows.length > 1){ document.windows.forEach((win,index) => { if (index != 0){ console.log("close " + index) win.close() } }) }
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

DocumentWindow Instance Properties

Here are the properties of the DocumentWindow class:

A script that sets the value of the focus property:

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 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:

droppedProjects = new Array() library.apply(function(item){ if (item instanceof Project && item.status === Project.Status.Dropped){ droppedProjects.push(item) } }) if(droppedProjects){ document.windows[0].perspective = Perspective.BuiltIn.Projects document.windows[0].focus = droppedProjects }
omnifocus://localhost/omnijs-run?script=try%7BdroppedProjects%20%3D%20new%20Array%28%29%0Alibrary%2Eapply%28function%28item%29%7B%0A%09if%20%28item%20instanceof%20Project%20%26%26%20item%2Estatus%20%3D%3D%3D%20Project%2EStatus%2EDropped%29%7B%0A%09%09droppedProjects%2Epush%28item%29%0A%09%7D%0A%7D%29%0Aif%28droppedProjects%29%7B%0A%09document%2Ewindows%5B0%5D%2Eperspective%20%3D%20Perspective%2EBuiltIn%2EProjects%0A%09document%2Ewindows%5B0%5D%2Efocus%20%3D%20droppedProjects%0A%7D%7Dcatch%28err%29%7Bconsole%2Elog%28err%29%7D

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.

var tasks = new Array() document.windows[0].content.rootNode.apply((item) => { if (item.object instanceof Task) { tasks.push(item); } }) if(tasks != []){ document.windows[0].content.select(tasks) }
omnifocus://localhost/omnijs-run?script=try%7Bvar%20tasks%20%3D%20new%20Array%28%29%0Adocument%2Ewindows%5B0%5D%2Econtent%2ErootNode%2Eapply%28%28item%29%20%3D%3E%20%7B%0A%09if%20%28item%2Eobject%20instanceof%20Task%29%20%7B%0A%09%09tasks%2Epush%28item%29%3B%0A%09%7D%0A%7D%29%0Aif%28tasks%20%21%3D%20%5B%5D%29%7B%0A%09document%2Ewindows%5B0%5D%2Econtent%2Eselect%28tasks%29%0A%7D%7Dcatch%28err%29%7Bconsole%2Elog%28err%29%7D

Here's a variation of the previous script that will select all of the tasks and/or projects in the current content view:

content-selection-choose-sheet
/*{ "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

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

var allProjects = flattenedProjects var targetName = "Project A" var targetProject = null for (i = 0; i < allProjects.length; i++){ var project = allProjects[i] if (project.name === targetName){ targetProject = project break } } if(targetProject){ document.windows[0].perspective = Perspective.BuiltIn.Projects Timer.once(1,function(timer){ document.windows[0].selectObjects([targetProject]) }) }
document.windows[0].perspective = Perspective.BuiltIn.Forecast Timer.once(1,function(timer){ var now = new Date() var today = Calendar.current.startOfDay(now) var dc = new DateComponents() dc.day = 7 var targetDate = Calendar.current.dateByAddingDateComponents(today,dc) var fday = document.windows[0].forecastDayForDate(targetDate) document.windows[0].selectForecastDays([fday]) })
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
document.windows[0].perspective = Perspective.BuiltIn.Forecast Timer.once(1,function(timer){ var now = new Date() var today = Calendar.current.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 = Calendar.current.dateByAddingDateComponents(today,dc) fday = document.windows[0].forecastDayForDate(targetDate) fdays.push(fday) } document.windows[0].selectForecastDays(fdays) })
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

NOTE: These examples use properties and functions of the shared Calendar class to calculate dates.

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 items: allObjects

Document > Window > Selection

document.windows[0].selection.database 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:

selectedTasks = document.windows[0].selection.tasks taskTitles = selectedTasks.map(task => task.name) console.log(taskTitles)
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

Move selected projects into new top-level project group:

items = document.windows[0].selection.projects if(items.length > 0){moveSections(items, new Folder("Project Group"))}
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

DatabaseDocument Class

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

var windowPromise = document.newWindow() windowPromise.then(function(win){ win.perspective = Perspective.BuiltIn.Projects }) windowPromise.catch(function(error){ console.error(error.message) })
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
var windowPromise = document.newTabOnWindow(document.windows[0]) windowPromise.then(function(win){ win.perspective = Perspective.BuiltIn.Forecast }) windowPromise.catch(function(error){ console.error(error.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

Copy Tags Between 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.

An example plug-in for copying tags between tasks:

/*{ "type": "action", "targets": ["omnifocus"], "author": "Otto Automator", "identifier": "com.omni-automation.copy-tags-between-selected-tasks", "version": "1.5", "description": "Append the tags of the chosen task to the other selected tasks.", "label": "Copy Tags between Selected Tasks", "shortLabel": "Copy Tags" }*/ (() => { var action = new PlugIn.Action(function(selection, sender){ // selection options: tasks, projects, folders, tags var selectedTasks = selection.tasks var taskNames = selectedTasks.map(function(task){ return task.name }) var inputForm = new Form() taskNames.forEach(function(taskName,index){ checkboxSwitch = new Form.Field.Checkbox( String(index), taskName, false ) inputForm.addField(checkboxSwitch) }) formPrompt = "Select the single task to copy tags from:" formPromise = inputForm.show(formPrompt,"Continue") inputForm.validate = function(formObject){ resultArray = Object.values(formObject.values) var count = 0; for (var i = 0; i < resultArray.length; i++) { if (resultArray[i] == true){count = count + 1} } return ((count == 1) ? true : false) } formPromise.then(function(formObject){ keys = Object.keys(formObject.values) for (var i = 0; i < keys.length; i++) { k = keys[i] if (formObject.values[k] == true){ var chosenTask = selectedTasks[Number(k)] var chosenTaskName = taskNames[Number(k)] } } str1 = "Copy the tags from “" + chosenTaskName + "” to the other selected tasks?" str2 = "Tags will be added to those tags already applied to the other selected tasks." alertMsg = str1.concat("\n\n",str2) var alert = new Alert("CONFIRMATION:", alertMsg) alert.addOption("Continue") alert.addOption("Cancel") var alertPromise = alert.show() alertPromise.then(function(result){ if (result == 0){ sourceTags = chosenTask.tags selectedTasks.forEach(function(task){ task.addTags(sourceTags) }) } }) }) }); action.validate = function(selection, sender){ // selection options: tasks, projects, folders, tags return (selection.tasks.length > 1) }; return action; })();

Displaying (selecting) an Item in the Window

While the focus property of the DocumentWindow class cna 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:

/*{ "type": "action", "targets": ["omnifocus"], "author": "Otto Automator", "identifier": "com.omni-automation.display-host-project", "version": "1.0", "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 task = selection.tasks[0] project = task.containingProject if(project){ projID = project.id.primaryKey urlStr = "omnifocus:///task/" + projID URL.fromString(urlStr).call(reply => {}) } }); action.validate = function(selection, sender){ // validation code // selection options: tasks, projects, folders, tags return (selection.tasks.length === 1) }; return action; })();

 01-10  The Action metadata.

 11-31  The main function containing the action code.

 24-28  The action validation routine will enable the action in the Automation menu when a single task is selected.

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

 15  The currently selected task is the first (and only) item in the selection array.

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

 17-21  A conditional for handling the project object.

 18  The value of the primaryKey property is a unique identifier string.

 19  Append the identifier string to URL string targeting the OmniFocus application.

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

DISCLAIMER