### Create OmniFocus Tutorial Project (JavaScript)
Source: https://omni-automation.com/omnifocus/tutorial/index
This script checks if an 'OmniFocus Tutorial' project exists. If not, it creates the project, sets it to sequential tasks, and adds tasks for each tutorial topic, linking to the corresponding HTML page. If the project exists, it opens the existing project and shows an alert. Requires OmniFocus and Omni Automation environment.
```javascript
var matchedProjects = flattenedProjects.filter(project => {return project.name === "OmniFocus Tutorial"})
console.log(matchedProjects)
if(matchedProjects.length === 0){
var project = new Project("OmniFocus Tutorial")
project.task.sequential = true
project.completedByChildren = true
var tutorialTopics = [{"title":"Introduction","page":"index.html"},{"title":"Console","page":"console.html"},{"title":"Inbox","page":"inbox.html"},{"title":"Due and Repeat","page":"task.html"},{"title":"Tags","page":"tag.html"},{"title":"Projects","page":"project.html"},{"title":"Plug-Ins","page":"plug-in.html"},{"title":"Cleanup and Restore","page":"cleanup.html"}]
var baseURL = "https://omni-automation.com/omnifocus/tutorial/"
tutorialTopics.forEach(topicObj => {
var tsk = new Task(topicObj.title,project)
tsk.note = baseURL + topicObj.page
})
var projectID = project.task.id.primaryKey
URL.fromString("omnifocus:///task/" + projectID).open()
} else {
var projectID = matchedProjects[0].task.id.primaryKey
URL.fromString("omnifocus:///task/" + projectID).open()
var alertMsg = "A project named “OmniFocus Tutorial” already exists."
new Alert("Existing Project",alertMsg).show()
}
```
--------------------------------
### HTTP GET with Basic Authentication Example
Source: https://omni-automation.com/shared/url-fetch-api
This example demonstrates how to make an HTTP GET request with Basic Authentication to retrieve data from a password-protected JSON file. It includes prompting the user for credentials and constructing the necessary Authorization header.
```APIDOC
## GET /secure/conference-sessions.json
### Description
Retrieves the contents of a password-protected JSON file using HTTP GET with Basic Authentication.
### Method
GET
### Endpoint
https://omni-automation.com/secure/conference-sessions.json
### Parameters
#### Query Parameters
None
#### Request Body
None
### Request Example
```javascript
// Omni Automation script to prompt for credentials and make the request
var url = "https://omni-automation.com/secure/conference-sessions.json"
var accountName = "user"
var accountPassword = "password"
var data = Data.fromString(accountName + ":" + accountPassword)
var credentials = data.toBase64()
var request = new URL.FetchRequest(url)
request.method = "GET"
request.headers = {
"Authorization": "Basic " + credentials
}
var response = URL.fetch(request)
if (response.statusCode == 200) {
console.log(response.bodyString)
} else {
console.log("Error: " + response.statusCode)
}
```
### Response
#### Success Response (200)
- **bodyData** (Data or null r/o) - Returns the raw HTTP body data from this response.
- **bodyString** (String or null r/o) - Interprets the bodyData as UTF–8 text.
- **headers** (Object r/o) - Returns the HTTP header fields for this response.
- **mimeType** (String or null r/o) - Returns the HTTP MIME type (e.g. text/plain, application/json).
- **statusCode** (Number r/o) - Returns the HTTP status code (e.g. 200, 404).
- **textEncodingName** (String or null r/o) - Returns the reported text encoding for this response.
- **url** (URL or null r/o) - Returns the URL for this response.
#### Response Example
```json
{
"sessions": [
{
"title": "Omni Automation Introduction",
"speaker": "John Doe"
}
]
}
```
```
--------------------------------
### StencilLib: Get Installed Stencil Names (JavaScript)
Source: https://omni-automation.com/libraries/index
This JavaScript function retrieves an array of names for all installed stencils in OmniGraffle. It iterates through available stencils and collects their names.
```javascript
(() => {
var StencilLib = new PlugIn.Library(new Version("1.0"));
// returns an array of the names of the installed stencils
StencilLib.getStencilNames = function() {
stencilNames = new Array()
app.stencils.forEach(function(aStencil){
stencilNames.push(aStencil.name)
})
return stencilNames
}
// ... other functions ...
return StencilLib;
})();
```
--------------------------------
### Version Handling
Source: https://omni-automation.com/omnigraffle/OG-API
API documentation for the `Version` class, covering its constructor, instance functions for version comparison (equals, atLeast, isAfter, isBefore), and properties.
```APIDOC
# `Version`
## Constructors
### `new Version(versionString: `String`)` → `Version`
Parses a string representation of a `Version` and returns an instance, or throws an error if the string isn’t a valid version.
## Instance Functions
### `function equals(version: `Version`)` → `Boolean`
Returns true if the receiving `Version` is equal to the argument `Version`.
### `function atLeast(version: `Version`)` → `Boolean`
Returns true if the receiving `Version` is at the same as or newer than the argument `Version`.
### `function isAfter(version: `Version`)` → `Boolean`
Returns true if the receiving `Version` is strictly after the argument `Version`.
### `function isBefore(version: `Version`)` → `Boolean`
Returns true if the receiving `Version` is strictly before the argument `Version`.
## Instance Properties
### `var versionString` → `String` _read-only_
Returns as an opaque string representation of the `Version`, suitable for display or logging. This should never be used in comparisons of any sort.
```
--------------------------------
### Prepare and Send Project Action Request in JavaScript
Source: https://omni-automation.com/openai/index
This snippet prepares a prompt with project details (title and description) and sends it to an OpenAI API for generating next steps. It includes a user confirmation step to warn about sending data to a third-party service. It uses `encodeURIComponent`, `Fetch.Request`, `Alert`, and `console`. Dependencies include `document`, `app`, `credentials`, `preferences`, `Alert`, `console`, and `Fetch`.
```javascript
project = selection.projects[0]
projectTitle = project.name
projectNote = project.note
promptString = "Given the following project title and description, "
promptString += "what are the next steps?"
promptString += "\n"
promptString += "Project Title: " + projectTitle
promptString += "\n"
promptString += "Project Description: " + projectNote
alertTitle = "Requesting Project Actions"
alertMessage = "IMPORTANT: Data about the selected project "
alertMessage += "will be sent to a third-party network service."
alert = new Alert(alertTitle, alertMessage)
alert.addOption("Proceed")
alert.addOption("Stop")
buttonIndex = await alert.show()
if(buttonIndex === 1){
throw {
name: "Cancel",
message: "User cancelled send."
}
}
console.log("# PROMPT", promptString)
escapedText = encodeURIComponent(promptString)
requestObj = {
"model": "gpt-3.5-turbo",
"messages": [{"role": "user", "content": escapedText}]
}
if(shouldLog){console.log("# PASSING CREDENTIALS AND REQUEST TO fetchData()")}
fetchData(credentialsObj, requestObj)
```
--------------------------------
### Get Stencil Object - JavaScript
Source: https://omni-automation.com/libraries/index
Retrieves the stencil object for a given stencil name. It first checks if the stencil is installed using `isStencilInstalled()`. If not installed, it displays an error message. If installed, it iterates through the application's stencils to find and return the matching stencil object.
```javascript
StencilLib.getStencilObject = function(stencilName){
if(this.isStencilInstalled(stencilName) === false){
displayErrorMessage("There is no stencil named: " + stencilName)
}
for(i = 0; i < app.stencils.length; i++){
if (app.stencils[i].name.localeCompare(stencilName) === 0){
return app.stencils[i]
}
}
}
```
--------------------------------
### OpenAI API Integration Setup (JavaScript)
Source: https://omni-automation.com/openai/index
Initializes OpenAI API integration within an Omni-Automation script. Sets up service details like the API endpoint and model, and defines helper functions for speech synthesis and credential management.
```JavaScript
/*{
"type": "action",
"targets": ["omnioutliner"],
"author": "Otto Automator",
"identifier": "com.omni-automation.oo.open-ai-essay-outline",
"version": "1.0",
"description": "This plug-in uses the Credentials class to create and retrieve log-in pairs. NOTE: to clear stored credentials, hold down Control modifier key when selecting plug-in from Automation menu. To set logging status, hold down the Option key when selecting plug-in from Automation menu. The “temperature”; setting refers to the degree of randomness or creativity in the responses generated by the model. A higher temperature setting will produce more unpredictable and diverse responses, while a lower setting will produce more conservative and predictable responses.",
"label": "OpenAI: Outline for Essay",
"shortLabel": "Essay Outline",
"paletteLabel": "Essay Outline",
"image": "wand.and.stars"
}*/
(() => {
/* DOCUMENTATION: https://platform.openai.com/docs/api-reference/introduction */
var serviceTitle = "OpenAI";
var serviceURLString = "https://api.openai.com/v1/completions"
var serviceModel = "text-davinci-003"
var credentials = new Credentials()
var preferences = new Preferences() // NO ID = PLUG-IN ID
var shouldLog
function createUtterance(textToSpeak){
AlexID = (
(app.platformName === "macOS") ?
"com.apple.speech.synthesis.voice.Alex" :
"com.apple.speech.voice.Alex"
)
voiceObj = Speech.Voice.withIdentifier(AlexID)
voiceRate = 0.4
utterance = new Speech.Utterance(textToSpeak)
utterance.voice = voiceObj
utterance.rate = voiceRate
return utterance
}
const requestCredentials = async () => {
try {
// CREATE FORM FOR GATHERING CREDENTIALS
inputForm = new Form()
// CREATE TEXT FIELDS
orgIDField = new Form.Field.String(
"organizationID",
"Org ID",
null
)
APIKeyField = new Form.Field.String(
"APIkey",
"API Key",
null
)
// ADD THE FIELDS TO THE FORM
inputForm.addField(orgIDField)
inputForm.addField(APIKeyField)
// VALIDATE THE USER INPUT
inputForm.validate = formObject => {
organizationID = formObject.values["organizationID"]
orgIDStatus = (organizationID && organizationID.length > 0) ? true:false
APIkey = formObject.values["APIkey"]
APIKeyStatus = (APIkey && APIkey.length > 0) ? true:false
validation = (orgIDStatus && APIKeyStatus) ? true:false
return validation
}
// PRESENT THE FORM TO THE USER
formPrompt = "Enter OpenAI Organization ID and API Key:"
formObject = await inputForm.show(formPrompt, "Continue")
// RETRIEVE FORM VALUES
organizationID = formObject.values["organizationID"]
APIkey = formObject.values["APIkey"]
// STORE THE VALUES
credentials.write(serviceTitle, organizationID, APIkey)
if(shouldLog){console.log("# CREDENTIALS STORED IN SYSTEM KEYCHAIN")}
}
catch(err){
if(!err.causedByUserCancelling){
new Alert(err.name, err.message).show()
}
}
}
const fetchData = async (credentialsObj, requestObj) => {
try {
organizationID = credentialsObj["user"]
APIkey = credentialsObj["password"]
if(shouldLog){console.log("# ORGANIZATION-ID:", organizationID)}
if(shouldLog){console.log("# API-KEY:", APIkey)}
if(shouldLog){console.log("# CONSTRUCTING URL.FetchRequest()")}
if(shouldLog){console.log("# SERVICE URL STRING:", serviceURLString)}
```
--------------------------------
### Get and Set Window Perspective
Source: https://omni-automation.com/omnifocus/window
This snippet demonstrates how to get the current perspective object of an OmniFocus window and how to set a new perspective. It accesses the `perspective` property of the first window in `document.windows`. The example shows setting the perspective to `Perspective.BuiltIn.Inbox`.
```javascript
// get the current perspective object
document.windows[0].perspective
//--> [object Perspective.BuiltIn: Projects]
// set the perspective
document.windows[0].perspective = Perspective.BuiltIn.Inbox
```
--------------------------------
### Get Identifiers of Installed Plug-Ins
Source: https://omni-automation.com/plugins/calling
Retrieves a list of all installed plug-in identifiers in an Omni application. This is useful for managing and referencing plug-ins within scripts. It utilizes the PlugIn.all property to access all plug-ins and maps their identifiers.
```javascript
var pluginIDs = PlugIn.all.map(plugin => plugin.identifier)
console.log(pluginIDs.join("\n"))
```
--------------------------------
### Creating and Populating Projects in OmniFocus using JavaScript
Source: https://omni-automation.com/omnifocus/tutorial/outline
This JavaScript snippet shows how to create a new project in OmniFocus, set its properties, and add tasks to it. It utilizes the `Project` class constructor and task manipulation methods. The output confirms the creation and population of the project.
```javascript
const newProject = new Project("New Project Name");
newProject.parallelStatus = "DoParallel"; // Or "DoSequentially"
const task1 = new Task("First Task");
newProject.addTask(task1);
const task2 = new Task("Second Task");
newProject.addTask(task2);
console.log(`Created project '${newProject.name}' with ${newProject.taskCount} tasks.`);
```
--------------------------------
### Accessing a Specific Level Style
Source: https://omni-automation.com/omnioutliner/style-levels
Shows how to get a reference to a specific level style by its nesting depth (starting from 0 for the first level).
```APIDOC
## GET /document/outline/levelStyle(depth:Number)
### Description
Returns the level style for the specified nesting level. If the level does not exist, it may be created.
### Method
GET
### Endpoint
`/document/outline/levelStyle(depth:Number)`
### Parameters
#### Path Parameters
- **depth** (Number) - Required - The nesting level (0-indexed) for which to retrieve the style.
### Request Example
```javascript
// Get the style for the 5th level (index 4)
let styleLevel4 = document.outline.levelStyle(4);
console.log(styleLevel4);
// This will also add levels 1 through 4 if they don't exist, and then return the style for level 4.
console.log(document.outline.levelStyles.length);
```
### Response
#### Success Response (200)
- **style** (Style) - The Style object for the specified level.
#### Response Example
```json
{
"fontName": "Helvetica",
"fontSize": 10,
"fontColor": "#666666"
}
```
```
--------------------------------
### Project
Source: https://omni-automation.com/omnifocus/OF-API
Documentation for the `Project` class, including class functions, constructors, and instance functions.
```APIDOC
# `Project` : `DatabaseObject`
## Class Functions
### `function byIdentifier(identifier: `String`)` → `Project` or `null`
Returns the `Project` with the specified identifier, or `null` if no such project exists.
## Constructors
### `new Project(name: `String`, position: `Folder` or `Folder.ChildInsertionLocation` or `null`)` → `Project`
## Instance Functions
### `function taskNamed(name: `String`)` → `Task` or `null`
Returns the first top-level `Task` in this project the given name, or `null`.
### `function appendStringToNote(stringToAppend: `String`)`
Appends `stringToAppend` to the end of the `Project`’s root `Task`’s `note`.
```
--------------------------------
### Call Omni Automation Library Functions (ShapeLib Example)
Source: https://omni-automation.com/libraries/call
This example demonstrates calling functions from a loaded Omni Automation library, specifically the ShapeLib. It first loads the library using the `loadLibrary` function and then calls `addShapeWithParameters` to create different shapes on the canvas. Dependencies include the ShapeLib being installed.
```javascript
function loadLibrary(plugInID,libraryName){
try {
plugInIDs = PlugIn.all.map(function(plugin){return plugin.identifier})
if (plugInIDs.includes(plugInID)){
plugIn = PlugIn.find(plugInID)
} else {
throw new Error("PlugIn not installed")
}
libraryNames = plugIn.libraries.map(function(library){return library.name})
if (libraryNames.includes(libraryName)){
return plugIn.library(libraryName)
} else {
throw new Error("Library not in PlugIn")
}
} catch(err){
errTitle = "MISSING RESOURCE"
alert = new Alert(errTitle,err.message).show(function(result){})
throw err.message
}
}
shapeLib = loadLibrary("com.omni-automation.libraries.ShapeLib","ShapeLib")
shapeLib.addShapeWithParameters( 'Star', // shape type new Rect(0,0,100,100), // shape rect Color.yellow, // fill color Color.red, // stroke color 4 // stroke thickness )
shapeLib.addShapeWithParameters( 'Circle', new Rect(110,0,100,100), Color.green, Color.blue, 4 )
shapeLib.addShapeWithParameters( 'Diamond', new Rect(220,0,100,100), Color.red, Color.gray, 4 )
```
--------------------------------
### OpenAI API Request Setup in Omni Automation
Source: https://omni-automation.com/openai/index
Initializes variables and sets up the OpenAI API service URL and model. It also instantiates Credentials and Preferences objects for managing user data and settings within the Omni Automation environment. Logging status is determined by the 'shouldLog' variable.
```javascript
/* DOCUMENTATION: https://platform.openai.com/docs/api-reference/introduction */
var serviceTitle = "OpenAI";
var serviceURLString = "https://api.openai.com/v1/completions"
var serviceModel = "text-davinci-003"
var credentials = new Credentials()
var preferences = new Preferences() // NO ID = PLUG-IN ID
var shouldLog
var promptString
```
--------------------------------
### OmniPlan Basic Action Template (AppleScript)
Source: https://omni-automation.com/console/plug-in-template
A foundational template for creating OmniPlan plug-in actions using AppleScript and Javascript. It includes essential metadata like type, author, identifier, and version, along with example code for executing an action and validating its conditions. The action itself displays a 'Hello World!' alert.
```javascript
/*{
"type": "action",
"targets": ["TARGET_NAME"],
"author": "AUTHOR-NAME",
"identifier": "ORGANIZATION_NAME.op.ACTION_NAME",
"version": "1.0",
"description": "The plug-in description goes here.",
"label": "ACTION_NAME",
"shortLabel": "ACTION_NAME",
"paletteLabel": "ACTION_NAME",
"image": "gearshape.fill"
}*/
(() => {
const action = new PlugIn.Action(async function(selection, sender){
// action code
// selection options: project, tasks, resources
try {
// PROCESSING STATEMENTS
new Alert("GREETINGS", "Hello World!").show()
}
catch(err){
new Alert(error.name, err.message).show()
console.error(err)
}
});
action.validate = function(selection, sender){
// validation code
// selection options: project, tasks, resources
return true
};
return action;
})();
```
--------------------------------
### Getting the OmniGraffle Application Name
Source: https://omni-automation.com/omnigraffle/big-picture
Demonstrates how to access the 'name' property of the 'app' object, which represents the OmniGraffle application. This is a basic example of interacting with the application object.
```javascript
app.name
--> OmniGraffle
```
--------------------------------
### Obsidian Helper Plug-In Metadata and Initialization
Source: https://omni-automation.com/obsidian/og-obsidian-helper
This JavaScript code snippet defines the metadata for the Obsidian Helper plug-in, including its author, version, identifier, and description. It initializes the plug-in by setting up preferences and defining the main action to be performed. The action involves creating a form to gather user input for Obsidian file operations.
```javascript
/*{
"type": "action",
"targets": ["omnigraffle"],
"author": "Otto Automator",
"identifier": "com.omni-automation.og.obsidian-helper",
"version": "1.0",
"description": "Creates or opens pages in Obsidian based upon the current document and canvas titles. If the creation option is chosen, plug-in exports the current canvas as an image in PNG format, using the current PNG export settings. The created file is named using this format: Document Title > Canvas Name",
"label": "Obsidian Helper",
"shortLabel": "Obsidian Helper",
"paletteLabel": "Obsidian Helper",
"image": "square.and.pencil.circle.fill"
}*/
(() => {
const preferences = new Preferences()
const action = new PlugIn.Action(async function(selection, sender){
try {
vaultTitle = preferences.readString("vaultTitle")
vaultTitleInput = new Form.Field.String(
"vaultTitle",
"in Vault",
vaultTitle,
null
)
cnvs = document.windows[0].selection.canvas
canvasTitle = cnvs.name
documentName = document.name
if(documentName.endsWith(".graffle")){
documentName = documentName.split(".graffle")[0]
}
defaultObsidianFileName = documentName + " > " + canvasTitle
actionOptions = ["Create New Content","Open Existing File"]
actionOptionIndx = preferences.readNumber("actionOptionIndx")
if(actionOptionIndx === null){actionOptionIndx = 0}
console.log("actionOptionIndx", actionOptionIndx)
actionMenu = new Form.Field.Option(
"actionOptionIndx",
"Action",
[0,1],
actionOptions,
actionOptionIndx
)
writeOptions = ["Overwrite Existing File", "Append to Existing File", "Add an Incremental Copy"]
writeOptionsIndx = preferences.readNumber("writeOptionsIndx")
if(writeOptionsIndx === null){writeOptionsIndx = 0}
console.log("writeOptionsIndx", writeOptionsIndx)
writeOptionsMenu = new Form.Field.Option(
"writeOptionsIndx",
"Creation Behavior",
[0,1,2],
writeOptions,
writeOptionsIndx
)
obsidianFileNameInput = new Form.Field.String(
"fileName",
"File Name",
defaultObsidianFileName,
null
)
inputForm = new Form()
inputForm.addField(obsidianFileNameInput)
inputForm.addField(vaultTitleInput)
inputForm.addField(actionMenu)
inputForm.addField(writeOptionsMenu)
formPrompt = "Create | Open Obsidian file:"
inputForm.validate = function(formObject){
vaultTitle = formObject.values["vaultTitle"]
fileName = formObject.values["fileName"]
return (vaultTitle && fileName) ? true:false
}
// RETRIEVE THE CHOSEN SETTINGS AND TITLES
formObject = await inputForm.show(formPrompt,"Continue")
vaultTitle = formObject.values["vaultTitle"]
preferences.write("vaultTitle", vaultTitle)
console.log("vaultTitle", vaultTitle)
encodedVaultTitle = encodeURIComponent(vaultTitle)
fileName = formObject.values["fileName"]
encodedFileName = encodeURIComponent(fileName)
actionOptionIndx = formObject.values["actionOptionIndx"]
preferences.write("actionOptionIndx", actionOptionIndx)
console.log("actionOptionIndx", actionOptionIndx)
writeOptionsIndx = formObject.values["writeOptionsIndx"]
preferences.write("writeOptionsIndx", writeOptionsIndx)
console.log("writeOptionsIndx", writeOptionsIndx)
if (actionOptionIndx === 0){
// EXPORT CANVAS IMAGE TO CLIPBOARD
cnvs = document.windows[0].selection.canvas
exportName = cnvs.name + ".png"
fileTypeID = "public.png"
wrapper = await document.makeFileWrapper(exportName, fileTypeID)
```
--------------------------------
### JavaScript: Create and Validate Start/End Date Fields
Source: https://omni-automation.com/actions/forms-examples
This snippet initializes an input form and adds two date fields: 'startDate' and 'endDate'. It defines validation logic ensuring the start date is in the future and the end date is after the start date. The code also handles promise resolution for the form submission and rejection for cancellation.
```javascript
var inputForm = new Form()
var startDateField = new Form.Field.Date( "startDate", "Start Date", null )
var endDateField = new Form.Field.Date( "endDate", "End Date", null )
inputForm.addField(startDateField)
inputForm.addField(endDateField)
var formPrompt = "Enter the start and end dates:"
var buttonTitle = "Continue"
var formPromise = inputForm.show(formPrompt, buttonTitle)
inputForm.validate = function(formObject){
currentDateTime = new Date()
startDateObject = formObject.values["startDate"]
startDateStatus = (startDateObject && startDateObject > currentDateTime) ? true:false
endDateObject = formObject.values["endDate"]
endDateStatus = (endDateObject && endDateObject > startDateObject) ? true:false
validation = (startDateStatus && endDateStatus) ? true:false
return validation
}
formPromise.then(function(formObject){
var StartDate = formObject.values['startDate']
var EndDate = formObject.values['endDate']
})
formPromise.catch(function(err){
console.log("form cancelled", err.message)
})
```
--------------------------------
### Get All Voice Instances (JavaScript)
Source: https://omni-automation.com/shared/speech
Retrieves an array containing all currently installed Speech.Voice instances on the system. This provides access to available voices for text-to-speech functionality.
```javascript
Speech.Voice.allVoices
//--> [[object Speech.Voice], [object Speech.Voice], [object Speech.Voice], [object Speech.Voice], [object Speech.Voice], [object Speech.Voice], [object Speech.Voice], [object Speech.Voice], [object Speech.Voice], [object Speech.Voice], …] (75)
```
--------------------------------
### Log Properties of All Installed Plug-Ins
Source: https://omni-automation.com/plugins/api
Iterates through all installed plug-ins using the PlugIn.all property and logs various details for each plug-in, including its display name, identifier, version, author, description, and URL. This is useful for discovering and inspecting available plug-ins. The code utilizes a forEach loop and console.log statements.
```javascript
PlugIn.all.forEach((plugin, index) => { if (index != 0){console.log(" ")} console.log("FILENAME:", plugin.displayName) console.log("ID:", plugin.identifier) console.log("VERSION:", plugin.version.versionString) console.log("AUTHOR:", plugin.author) console.log("DESC:", plugin.description) console.log("URL:", plugin.URL.string) })
```
--------------------------------
### Interacting with Stencils in OmniGraffle
Source: https://omni-automation.com/omnigraffle/big-picture
Provides examples of how to interact with stencils within the OmniGraffle application. It shows how to get the count of available stencils and access the name of the first stencil.
```javascript
app.stencils.length
app.stencils[0].name
```
--------------------------------
### OmniFocus Tutorial Project Creation via URL (Encoded JavaScript)
Source: https://omni-automation.com/omnifocus/tutorial/index
This is an encoded JavaScript snippet designed to be executed via an OmniJS URL scheme. It performs the same functionality as the first snippet: checking for, creating, and populating the 'OmniFocus Tutorial' project. This format is useful for direct invocation from external sources.
```javascript
try{var matchedProjects = flattenedProjects.filter(project => {return project.name === "OmniFocus Tutorial"})
console.log(matchedProjects)
if(matchedProjects.length === 0){
var project = new Project("OmniFocus Tutorial")
project.task.sequential = true
project.completedByChildren = true
var tutorialTopics = [{"title":"Introduction","page":"index.html"},{"title":"Console","page":"console.html"},{"title":"Inbox","page":"inbox.html"},{"title":"Due and Repeat","page":"task.html"},{"title":"Tags","page":"tag.html"},{"title":"Projects","page":"project.html"},{"title":"Plug-Ins","page":"plug-in.html"},{"title":"Cleanup and Restore","page":"cleanup.html"}]
var baseURL = "https://omni-automation.com/omnifocus/tutorial/"
tutorialTopics.forEach(topicObj => {
var tsk = new Task(topicObj.title,project)
tsk.note = baseURL + topicObj.page
})
var projectID = project.task.id.primaryKey
URL.fromString("omnifocus:///task/" + projectID).open()
} else {
var projectID = matchedProjects[0].task.id.primaryKey
URL.fromString("omnifocus:///task/" + projectID).open()
var alertMsg = "A project named “OmniFocus Tutorial” already exists."
new Alert("Existing Project",alertMsg).show()
}}catch(err){console.log(err)}
```
--------------------------------
### Example: Get Next Task Repetition Date
Source: https://omni-automation.com/omnifocus/task-repeat
This script demonstrates how to retrieve the next scheduled repetition date for a task using the `firstDateAfterDate` method of the `repetitionRule` property.
```APIDOC
## Date/Time of the Next Task Repetition
```javascript
var task = document.windows[0].selection.tasks[0]
if(task && task.repetitionRule){
console.log(task.name, task.repetitionRule.firstDateAfterDate(new Date()))
}
```
```
--------------------------------
### Create New Project with Tasks using JavaScript
Source: https://omni-automation.com/omnifocus/project
Demonstrates the creation of a new project and subsequently adding tasks to it. The `Project` constructor is used to create the project, and the `Task` constructor is used to add tasks, associating them with the newly created project.
```javascript
var project = new Project("My Top-Level Project")
new Task("First Project Task", project)
new Task("Second Project Task", project)
```
--------------------------------
### Find Tags Matching a Pattern with Omni Automation
Source: https://omni-automation.com/omnifocus/database
This script demonstrates how to find all tags in OmniFocus that match a given string pattern using smart matching. The example searches for tags starting with 'Auto-'.
```javascript
tagsMatching("Auto-")
```
--------------------------------
### Installable OmniFocus Project Action from Outline Item (Omni Automation)
Source: https://omni-automation.com/omnioutliner/app-to-app-04
This code defines an installable Omni Automation plug-in action for OmniOutliner. It performs the same function as the direct script: creating an OmniFocus project from a selected outline item and its children. The `validate` function ensures the action can only be run when a single top-level outline item is selected.
```javascript
/*{ "type": "action", "targets": ["omnioutliner"], "author": "Otto Automator", "version": "1.1", "identifier": "com.omni-automation.oo-of.new-project-with-actions" "description": "Creates new OmniFocus project from the selected row, and uses row children for project actions.", "label": "Item to Project", "shortLabel": "Item to Project" }*/ (() => {
var action = new PlugIn.Action(function(selection, sender) {
// action code
// selection options: columns, document, editor, items, nodes, styles
node = selection.nodes[0]
editor = selection.editor
node.expand(true)
editor.select([node])
editor.select(node.children,true)
editor.copyNodes(editor.selectedNodes, Pasteboard.general)
url = "omnifocus:///paste?target=projects"
URL.fromString(url).open()
});
action.validate = function(selection, sender) {
// validation code
// selection options: columns, document, editor, items, nodes, styles
return (selection.nodes.length === 1 && selection.nodes[0].level === 1)
};
return action;
})();
```
--------------------------------
### Get Specific Weekday Occurrence (JavaScript)
Source: https://omni-automation.com/shared/calendar
This snippet demonstrates using the previously defined weekdayOccurrencesInMonth function to find a specific occurrence of a weekday in a given month and year. It retrieves the second Monday of May 2021 as an example.
```javascript
var secondMonday = weekdayOccurrencesInMonth(1, 5, 2021)[1]
console.log(secondMonday)
```
--------------------------------
### Create New Folder with Projects using JavaScript
Source: https://omni-automation.com/omnifocus/project
Illustrates how to create a new folder and then populate it with multiple new projects. The `Folder` constructor creates the container, and subsequent `Project` constructor calls with the folder as a parameter add projects within that folder.
```javascript
var masterFolder = new Folder("Master Project")
new Project("Preparation", masterFolder)
new Project("Build", masterFolder)
new Project("Finish",masterFolder)
```
--------------------------------
### Get and Set Default Start Time Setting (JavaScript)
Source: https://omni-automation.com/omnifocus/settings
Illustrates how to retrieve and modify the 'DefaultStartTime' setting. It shows fetching the default value, the current value, setting a new value, and then resetting it to the default.
```javascript
settings.defaultObjectForKey('DefaultStartTime')
//--> "00:00"
settings.objectForKey('DefaultStartTime')
//--> "00:00"
settings.setObjectForKey('01:00','DefaultStartTime')
//--> "01:00"
//--> How to reset time setting to default value
defaultValue = settings.defaultObjectForKey('DefaultStartTime')
settings.setObjectForKey(defaultValue,'DefaultStartTime')
```
--------------------------------
### Example Voice Control Open URL Command XML (Application-Specific)
Source: https://omni-automation.com/voice-control/script-new-run-omni-script
An example of the XML structure for a Voice Control Open URL command configured for application-specific scope. This XML includes the application name and ID, along with the command details and the URL for an Omni Automation script.
```xml
Custom.672708148.08394381
CustomAppName
OmniFocus
CustomCommands
en_US
Show Greeting
CustomModifyDate
2022-04-26T16:22:28Z
CustomScope
com.omnigroup.OmniFocus3
CustomType
URL
CustomURLStringList
omnifocus://localhost/omnijs-run?script=new%20Alert%28%22Greeting%22%2C%20%22Hello%20World%21%22%29%2Eshow%28%29
Enabled
```
--------------------------------
### Example Voice Control Open URL Command XML (System-Wide)
Source: https://omni-automation.com/voice-control/script-new-run-omni-script
An example of the XML structure for a Voice Control Open URL command configured for system-wide scope. This XML defines the command name, type, scope, and the URL to be executed, which in this case is an Omni Automation script.
```xml
Custom.672708148.08394381
CustomCommands
en_US
Show Greeting
CustomModifyDate
2022-04-26T16:22:28Z
CustomScope
com.apple.speech.SystemWideScope
CustomType
URL
CustomURLStringList
omnifocus://localhost/omnijs-run?script=new%20Alert%28%22Greeting%22%2C%20%22Hello%20World%21%22%29%2Eshow%28%29
Enabled
```
--------------------------------
### Get Action Names in Plug-In (JavaScript)
Source: https://omni-automation.com/actions/index
Retrieves a list of action names from a specified plug-in. Requires the plug-in's ID. Returns an array of strings, or throws an error if the plug-in is not installed.
```javascript
function getActionNamesInPlugIn(PlugInID){
var aPlugin = PlugIn.find(PlugInID)
if (aPlugin == null){
throw new Error("Plugin is not installed.")
}
var actionNames = aPlugin.actions.map(function(action){
return action.name
})
return actionNames
}
```
--------------------------------
### Help Me Plan Plug-In Logic (JavaScript)
Source: https://omni-automation.com/shared/alm-plug-in-05
This JavaScript code defines the 'Help Me Plan' plug-in, which leverages Apple Foundation Models to generate task steps. It requires macOS, iOS, iPadOS, and visionOS 26+, and OmniFocus 4.8+. The plug-in takes a task's name and note as input, prompts the AFM for planning steps, and creates new sub-tasks for each suggested step. It includes error handling and utility functions for task manipulation and UI interaction.
```javascript
/*{
"author": "Ken Case",
"targets": ["omnifocus"],
"type": "action",
"identifier": "com.omnigroup.kcase.help-me-plan",
"version": "1.1",
"description": "A plug-in that helps me plan a task",
"label": "Help Me Plan",
"mediumLabel": "Help Me Plan",
"longLabel": "Help Me Plan",
"paletteLabel": "Help Me Plan",
"image": "apple.intelligence"
}*/
(() => {
const schema = LanguageModel.Schema.fromJSON({
arrayOf: {
name: "task-schema",
properties: [
{name: "name", isOptional: false},
{name: "note", isOptional: true},
]
}
});
const session = new LanguageModel.Session();
const helpMePlanTask = async (task, selection) => {
const temporaryItem = addResponseItemToTask({"name": "Thinking…", "note": ""}, task);
console.log("Processing Task:", task.name);
console.log("Schema:", schema);
console.log("Session:", session);
const taskProperties = {"name": task.name, "note": task.note};
console.log("Task properties:", taskProperties);
const prompt = "You're a GTD expert helping someone plan out a project in OmniFocus. Provide a list of steps for the following JSON task: " + JSON.stringify(taskProperties);
const responseJSON = await session.respondWithSchema(prompt, schema);
console.log(responseJSON);
const response = JSON.parse(responseJSON);
for (const responseItem of response) {
addResponseItemToTask(responseItem, task);
}
expandNotes(task, selection.window);
selection.database.deleteObject(temporaryItem);
}
const addResponseItemToTask = (responseItem, task) => {
let responseTask = new Task(responseItem.name, task);
responseTask.note = responseItem.note;
return responseTask
}
const expandNotes = (object, window) => {
console.log("expandNotes: object = ", object);
const contentTree = window.content;
const node = contentTree.nodeForObject(object);
node.expandNote(true);
}
const saveEdits = (selection) => {
const previousSelection = selection.databaseObjects;
selection.window.selectObjects([]);
selection.window.selectObjects(previousSelection);
}
const action = new PlugIn.Action(async (selection) => {
try {
console.log("Help me plan…");
saveEdits(selection);
const projects = selection.projects;
for (const project of projects) {
await helpMePlanTask(project.task, selection);
}
const tasks = selection.tasks;
for (const task of tasks) {
await helpMePlanTask(task, selection);
}
} catch (err) {
console.error(err.name, err.message)
new Alert(err.name, err.message).show()
}
});
return action;
})();
```
--------------------------------
### OmniFocus: Validate Single Task Starting with 'Call'
Source: https://omni-automation.com/plugins/bundle
An example validation function specific to OmniFocus that checks if exactly one task is selected and its name begins with the string 'Call'. It returns true if the condition is met, otherwise false.
```javascript
action.validate = function(selection, sender){
return (
selection.tasks.length === 1 &&
selection.tasks[0].name.startsWith("Call")
)
};
```
--------------------------------
### 1st-Run Interaction Plug-In using JavaScript
Source: https://omni-automation.com/shared/preferences
This JavaScript plug-in utilizes the Preferences class to detect and manage the first-time execution of an automation script. It displays a welcome message on the initial run and allows users to reset the first-run status by holding the Control key during invocation. Dependencies include the Preferences class and the Alert class for user interaction. It has no specific input requirements but outputs messages and user prompts.
```javascript
/*{
"type": "action",
"targets": ["omnifocus","omniplan","omnigraffle","omnioutliner"],
"author": "Otto Automator",
"identifier": "com.omni-automation.all.first-run-sensor",
"version": "1.0",
"description": "This plug-in will present an alert the first time it is executed. To reset the plug-in, hold down Control key when selecting from Automation menu.",
"label": "First Run Example",
"shortLabel": "First Run Example",
"paletteLabel": "First Run Example",
"image": "1.brakesignal"
}*/
(() => {
var preferences = new Preferences()
const action = new PlugIn.Action(async function(selection, sender){
incrementedCount = preferences.readNumber("incrementedCount")
if(!incrementedCount){
preferences.write("incrementedCount", 0)
incrementedCount = 0
}
if (app.controlKeyDown){
alertMessage = "Reset the stored count?"
alert = new Alert("Confirmation Required", alertMessage)
alert.addOption("Reset")
alert.addOption("Cancel")
buttonIndex = await alert.show()
if (buttonIndex === 0){
preferences.write("incrementedCount", 0)
console.log("incrementedCount", "reset")
return "user reset"
}
}
console.log("incrementedCount", incrementedCount)
if (incrementedCount === 0){
alertTitle = "Plug-In 1st Run"
alertMessage = "Welcome to the 1st-Run Plug-In!"
await new Alert(alertTitle, alertMessage).show()
}
preferences.write("incrementedCount", incrementedCount + 1)
// PROCESSING CODE GOES HERE
});
action.validate = function(selection, sender){
return true
};
return action;
})();
```
--------------------------------
### Accessing Graphics within a Canvas Layer in OmniGraffle
Source: https://omni-automation.com/omnigraffle/big-picture
Provides examples of how to reference graphics within a specific layer of a canvas in OmniGraffle. It shows how to get the count of graphics and the name of the first graphic.
```javascript
canvases[0].layers[0].graphics.length
canvases[0].layers[0].graphics[0].name
```
--------------------------------
### Example OmniGraffle Plugin Call (JavaScript)
Source: https://omni-automation.com/libraries/index
This JavaScript code demonstrates how to find a specific OmniGraffle plugin and access its StencilLib library to import a graphic. It assumes the plugin with identifier 'com.NyhthawkProductions.OmniGraffle' is installed.
```javascript
aPlugin = PlugIn.find("com.NyhthawkProductions.OmniGraffle")
stencilLib = aPlugin.library("StencilLib")
stencilLib.importGraphicFromStencil('Tablet Mac','Google Material Design Icons')
```
--------------------------------
### Manage Plug-in Credentials and Logging
Source: https://omni-automation.com/openai/index
Handles the main action for the plug-in, including reading and writing preferences for logging, managing stored credentials (adding, removing, and checking for their existence), and controlling logging status through alerts.
```javascript
const action = new PlugIn.Action(async function(selection, sender){
try {
// READ PREFERENCES
booleanValue = preferences.readBoolean("shouldLog")
if(!booleanValue){
shouldLog = false
preferences.write("shouldLog", false)
}
if(shouldLog){console.clear()}
loggingMsg = (shouldLog) ? "# LOGGING IS ON":"# LOGGING IS OFF"
console.log(loggingMsg)
if (app.controlKeyDown){
// TO REMOVE CREDENTIALS HOLD DOWN CONTROL KEY WHEN SELECTING PLUG-IN
credentialsObj = credentials.read(serviceTitle)
if(!credentialsObj){
alertMessage = "There are no stored credentials to remove."
new Alert("Missing Resource", alertMessage).show()
} else {
alertMessage = "Remove the stored credentials?"
alert = new Alert("Confirmation Required", alertMessage)
alert.addOption("Reset")
alert.addOption("Cancel")
alert.show(buttonIndex => {
if (buttonIndex === 0){
console.log(`Removing Service “${serviceTitle}”`)
credentials.remove(serviceTitle)
console.log(`Service “${serviceTitle}” Removed`)
}
})
}
} else if (app.optionKeyDown){
alertMessage = (shouldLog) ? "Logging is on." : "Logging is off."
alert = new Alert("Logging Status", alertMessage)
alert.addOption("Turn On")
alert.addOption("Turn Off")
```
--------------------------------
### Get Stencil Names - JavaScript
Source: https://omni-automation.com/libraries/index
Retrieves a list of all installed stencil names in OmniGraffle. It iterates through the application's stencil collection and maps each stencil object to its name property, returning an array of strings.
```javascript
StencilLib.getStencilNames = function(){
return app.stencils.map(function(aStencil){return aStencil.name});
};
```