### 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}); }; ```