The “Big Picture”
Most scriptable applications are designed with a hierarchical organization where the scriptable elements are contained within other elements. For example, the OmniPlan application edits documents that contain projects that contain scenarios that contain tasks and resources.
In the OmniPlan Omni Automation scripting implementation:
- A Project represents the main contents of an OmniPlan Document and is used as the global object in any scripting session that is related to a particular document.
- A Scenario represents a set of Tasks and Resources and associated Schedules. The actuals for a Project are one Scenario, and saved baselines are the others.
The illustration below shows the hierarchical nature and relationships of the scriptable OmniPlan objects (both on macOS and iOS).
Application
In Omni Automation scripts, the application object is represented by the abbreviation: “app”. The application object is addressed by scripts to determine the current system platform, pressed modifier keys, and for opening documents. (see Application section)
Application Object
app.name
//--> OmniPlan
Documents
Although documents are the sole and primary element of the OmniPlan application, the current document is not referenced using the app object, but is referenced instead as a top-level object:
Document Object
document.name
//--> "Home Renovation"
For the sake of security, documents are not allowed to be accessed by scripts run in the consoles of other documents, so the application object will not return references to other documents.
Open Documents
//--> these are not supported
app.documents.length
app.documents[0]
Document Windows
In the OmniPlan scripting implementation, windows belong to documents, and their references include their parent implied document object:
Document > Window
Document Windows
document.windows.length
And the current window is always the first item in the list (array) of open windows:
Current Document Window
var currentWindow = document.windows[0]
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 three properties whose values are a single item reference (selection, project) or arrays of references (resources, tasks) to the objects selected in the window: project, resources, and tasks
Document > Window > Selection
Document Selection
document.windows[0].selection
//--> [object Selection]
document.windows[0].selection.project
//--> [object Project]
document.windows[0].selection.resources
//--> [[object Resource]]
document.windows[0].selection.tasks
//--> [[object Task],[object Task],[object Task]]
For example, here’s a simple script for getting the titles of the selected tasks:
Titles of Selected Tasks
var selectedTasks = document.windows[0].selection.tasks
var taskTitles = selectedTasks.map(task => task.title)
console.log(taskTitles.join('\n'))
Project
A Project represents the contents of an OmniPlan document, and when writing scripts that target the content of the current document, the project becomes the topmost object, providing properties whose values are references to the scenarios (actual and baselines) the project contains.
Project Object
document.project.title
//--> "90-Day Blank Project"
// The Project is the topmost object and can be referenced using the “this” keyword
this.title
//--> "90-Day Blank Project"
// Since the Project is the top-level item, it is implied and so you can simply use the property name
title
//--> "90-Day Blank Project"
Scenarios
A Scenario represents a set of tasks and resources and associated schedules. The actuals for a project are one scenario, and saved baselines are the others.
The project property “actual” references the current Scenario, which has properties of its own, such as hasFixedEndDate:
Current Scenario Object (actual)
actual
//--> [object Scenario]
actual.hasFixedEndDate
//--> false
The Project property baselineNames provides an array of the names of any other Scenarios, and references to those scenarios can be derived using the baselineNamed(…) scripting method:
Baselines
baselineNames
//--> [Baseline A, Baseline B]
baselineNamed("Baseline B")
//--> [object Scenario]
Also note that an instance of the Scenario class contains two properties representing the origin items of their Task and Resource elements. These “root” items are used when creating and managing additional instances of their classes.
“Root” Elements
actual.rootTask
//--> [object Task]
actual.rootResource
//--> [object Resource]
Resources
Instances of the Resources class represent the people, groups, and physical materials and equipment used by the project. A Resource is an element of a Scenario and is created and added to a scenario by using the addMember() method of the Resource class on the root resource object of the scenario.
Add a Resource
var resc = actual.rootResource.addMember()
resc.type = ResourceType.staff
resc.name = "Sala Mander"
resc.email = "salamander@acmeprojects.com"
The members property of the Resource class when used with the root resource object, will return an array of references to the top-level resources for the Scenario, as in this example script for getting the titles of a scenario’s top-level resources:
Top-Level Resources
var resNames = actual.rootResource.members.map(rsc => {return rsc.name})
console.log(resNames)
Creating a reference to an instance of the Resource class can be done using the resourceNamed() method of the parent instance of the Scenario class.
Reference Existing Resource
actual.resourceNamed("Target Resource Title")
//--> returns the 1st matching object reference if one exists, otherwise returns null
Tasks
A Task is anything that needs to get done in order for the project to move toward completion. Each task has attributes such as start and end dates, a completion percentage, and resource assignments.
A Task is an element of a Scenario and is created and added to a scenario by using the addSubtask() method of the Task class on the root task object of the scenario.
New Task
var newTask = actual.rootTask.addSubtask()
newTask.title = "NEW TASK"
The descendents() method of the Task class when used with the root task object, will return an array of references to the tasks in the entire tree of the scenario, as in this example script for getting all the task titles of a scenario:
Get Task Titles
var taskTitles = actual.rootTask.descendents().map(task => {return task.title})
console.log(taskTitles.join('\n'))
The property subtasks has a value that is an array of references to the subtasks of a specified task.
Creating a reference to an instance of the Task class can be done using the taskNamed() method of the parent instance of the Scenario class.
Task Reference
actual.taskNamed("Target Task Title")
//--> returns the 1st matching object reference if one exists, otherwise returns null