### Default Start Time Setting Source: https://omni-automation.com/omnifocus/settings.html Demonstrates retrieving and setting the 'DefaultStartTime' setting. Use `objectForKey` for general values and `setObjectForKey` to change them. The example also shows how to reset the time setting to its 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') ``` -------------------------------- ### Run OmniFocus Tutorial Project Installation Script Source: https://omni-automation.com/omnifocus/tutorial/index.html This is a URL that, when opened, executes the OmniFocus tutorial project installation script. It includes error handling to log any issues encountered during script execution. ```url omnifocus://localhost/omnijs-run?script=try%7Bvar%20matchedProjects%20%3D%20flattenedProjects%2Efilter%28project%20%3D%3D%3D%20%7Breturn%20project%2Ename%20%3D%3D%3D%20%22OmniFocus%20Tutorial%22%7D%29%0Aconsole%2Elog%28matchedProjects%29%0Aif%28matchedProjects%2Elength%20%3D%3D%3D%200%29%7B%0A%09var%20project%20%3D%20new%20Project%28%22OmniFocus%20Tutorial%22%29%0A%09project%2Etask%2Esequential%20%3D%20true%0A%09project%2EcompletedByChildren%20%3D%20true%0A%09var%20tutorialTopics%20%3D%20%5B%7B%22title%22%3A%22Introduction%22%2C%22page%22%3A%22index%2Ehtml%22%7D%2C%7B%22title%22%3A%22Console%22%2C%22page%22%3A%22console%2Ehtml%22%7D%2C%7B%22title%22%3A%22Inbox%22%2C%22page%22%3A%22inbox%2Ehtml%22%7D%2C%7B%22title%22%3A%22Due%20and%20Repeat%22%2C%22page%22%3A%22task%2Ehtml%22%7D%2C%7B%22title%22%3A%22Tags%22%2C%22page%22%3A%22tag%2Ehtml%22%7D%2C%7B%22title%22%3A%22Projects%22%2C%22page%22%3A%22project%2Ehtml%22%7D%2C%7B%22title%22%3A%22Plug%2DIns%22%2C%22page%22%3A%22plug%2Din%2Ehtml%22%7D%2C%7B%22title%22%3A%22Cleanup%20and%20Restore%22%2C%22page%22%3A%22cleanup%2Ehtml%22%7D%5D%0A%09var%20baseURL%20%3D%20%22https%3A%2F%2Fomni%2Dautomation%2Ecom%2Fomnifocus%2Ftutorial%2F%22%0A%09tutorialTopics%2EforEach%28topicObj%20%3D%3E%20%7B%0A%09%09var%20tsk%20%3D%20new%20Task%28topicObj%2Etitle%2Cproject%29%0A%09%09tsk%2Enote%20%3D%20baseURL%20%2B%20topicObj%2Epage%0A%09%7D%29%0A%09var%20projectID%20%3D%20project%2Etask%2Eid%2EprimaryKey%0A%09URL%2EfromString%28%22omnifocus%3A%2F%2F%2Ftask%2F%22%20%2B%20projectID%29%2Eopen%28%29%0A%7D%20else%20%7B%0A%09var%20projectID%20%3D%20matchedProjects%5B0%5D%2Etask%2Eid%2EprimaryKey%0A%09URL%2EfromString%28%22omnifocus%3A%2F%2F%2Ftask%2F%22%20%2B%20projectID%29%2Eopen%28%29%0A%09var%20alertMsg%20%3D%20%22A%20project%20named%20%E2%80%9COmniFocus%20Tutorial%E2%80%9D%20already%20exists%2E%22%0A%09new%20Alert%28%22Existing%20Project%22%2CalertMsg%29%2Eshow%28%29%0A%7D%7Dcatch%28err%29%7Bconsole%2Elog%28err%29%7D ``` -------------------------------- ### Focus Projects by Name Prefix Source: https://omni-automation.com/omnifocus/outline.html This script focuses on projects whose names start with a given prefix (e.g., "Get "). It collects matching projects and sets them as the focus for the window. ```javascript document.windows[0].focus = [] tree = document.windows[0].content items = [] tree.rootNode.apply(node => { item = node.object if(item instanceof Project){ if(item.name.startsWith("Get ")){items.push(item)} } }) if (items.length > 0){document.windows[0].focus = items} ``` -------------------------------- ### Initialize Preferences and Action Source: https://omni-automation.com/omnifocus/plug-in-import-icloud-taskpaper.html Sets up user preferences and defines the main plug-in action, including platform-specific iCloud URL generation and user setup for macOS. ```JavaScript (() => { preferences = new Preferences() const action = new PlugIn.Action(async function(selection, sender){ try { // GENERATE URL FOR “TaskPaper Templates” FOLDER WITHIN THE CURRENT OMNI APP ICLOUD FOLDER if (Device.current.iOS){ var iCloudURL = "file:///private/var/mobile/Library/Mobile%20Documents/" } else if (Device.current.mac){ if (app.controlKeyDown){ alertMessage = "Reset the stored user name?" alert = new Alert("Confirmation Required", alertMessage) alert.addOption("Reset") alert.addOption("Cancel") buttonIndex = await alert.show() if (buttonIndex === 0){ preferences.remove("userName") } } var currentUserName = preferences.readString("userName") if(!currentUserName){ alertTitle = "1st-Run Setup" alertMessage = "This plug-in scans for TaskPaper templates with a “.taskpaper” extension, stored in a “TaskPaper Templates” folder placed by you within the OmniFocus folder on your iCloud drive.\n\nIn the forthcoming chooser dialog, please select your Home folder." await new Alert(alertTitle, alertMessage).show() picker = new FilePicker() picker.folders = true picker.multiple = false chosenFolderURL = await picker.show() chosenFolderURL = chosenFolderURL[0].string chosenFolderURL = chosenFolderURL.substring(8); pathArray = chosenFolderURL.split('/') currentUserName = pathArray[1] preferences.write("userName", currentUserName) } var iCloudURL = `file:///Users/${currentUserName}/Library/Mobile%20Documents/` } appName = app.name lastSegment = `iCloud~com~omnigroup~${appName}/Documents/TaskPaper%20Templates/` combinedURLstr = iCloudURL + lastSegment sourceFolderURL = URL.fromString(combinedURLstr) // SEARCH THE DIRECTORY FOR MATCHING FILES filetype = TypeIdentifier.fromPathExtension("taskpaper", false) searchResults = await sourceFolderURL.find([filetype], false) if (searchResults.length === 0){ throw new Error("No files found.") } // DISPLAY MENU OF FILE NAMES menuItems = searchResults.map(function(url){ urlString = url.string lastItem = urlString.substring(urlString.lastIndexOf('/') + 1) lastItem = lastItem.replace(/\.[^/.]+$/, "") // file extension return decodeURIComponent(lastItem) }) menuIndexes = menuItems.map(function(item, index){return index}) templateMenu = new Form.Field.Option( "template", null, menuIndexes, menuItems, 0 ) destinations = ["Inbox", "Projects"] destinationMenu = new Form.Field.Option( "destination", null, [0,1], destinations, 0 ) inputForm = new Form() inputForm.addField(templateMenu) inputForm.addField(destinationMenu) formPrompt = "Template and destination:" buttonTitle = "Continue" formObject = await inputForm.show(formPrompt, buttonTitle) // PROCESS FORM RESULTS templateIndex = formObject.values['template'] chosenURL = searchResults[templateIndex] destinationIndex = formObject.values['destination'] destination = destinations[destinationIndex].toLowerCase() // PROCESS CHOSEN FILE chosenURL.fetch(function(data){ ``` -------------------------------- ### Show Projects Perspective (URL Scheme) Source: https://omni-automation.com/omnifocus/perspective.html This example demonstrates how to open the Projects perspective using the OmniFocus URL schema. This can be invoked from external applications or other scripts. ```javascript URL.fromString("omnifocus:///projects").open() ``` -------------------------------- ### Create Task at Inbox Beginning Source: https://omni-automation.com/omnifocus/tutorial/inbox.html Use the `inbox.beginning` property to insert a new task at the start of the inbox. ```javascript new Task("Task One", inbox.beginning) ``` -------------------------------- ### Plug-In Metadata Example Source: https://omni-automation.com/omnifocus/tutorial/plug-in.html Defines the core properties for an OmniFocus plug-in, including its type, target applications, author, identifier, version, and display labels. ```json { "type": "action", "targets": ["omnifocus"], "author": "Action Author", "identifier": "com.youOrCompany.of.actionName", "version": "1.0", "description": "Action Description", "label": "Menu Item Title", "shortLabel": "Toolbar Item Title", "paletteLabel": "Toolbar Item Title", "image": "gearshape.fill" } ``` -------------------------------- ### Get Settings Keys Source: https://omni-automation.com/omnifocus/settings.html Retrieves and logs a sorted list of all available database setting keys. This script is useful for understanding the configuration options available. ```javascript try{ console.log(settings.keys.sort().join("\n")) }catch(err){ console.log(err) } ``` -------------------------------- ### Activating a Tag Source: https://omni-automation.com/omnifocus/database-object.html Sets the 'active' property of a tag to true. This example assumes a tag with the name 'Camera-Ready' already exists. ```javascript var tag = flattenedTags.byName("Camera-Ready") if(tag){tag.active = true} ``` -------------------------------- ### Prepend Text to a Note Object Source: https://omni-automation.com/omnifocus/text.html Shows how to prepend text to an existing note object using the insert() function and the start property of the note object. ```javascript task = new Task("Example Task") task.note = "How Now Brown Cow" noteObj = task.noteText noteObj.insert(noteObj.start, new Text("Well ", noteObj.style)) noteObj.string //--> "Well How Now Brown Cow" ``` -------------------------------- ### Get and Set Key Value Source: https://omni-automation.com/omnifocus/settings.html Demonstrates retrieving and setting a boolean setting. Use `objectForKey` for general values, `boolForKey` for booleans, and `setBoolForKey` to change boolean values. ```javascript console.log("objectForKey: ", settings.objectForKey('InboxIsActive')) console.log("defaultObjectForKey: ", settings.defaultObjectForKey('InboxIsActive')) console.log("boolForKey: ", settings.boolForKey('InboxIsActive')) settings.setBoolForKey(false,'InboxIsActive') console.log("setBoolForKey: false") console.log("boolForKey: ", settings.boolForKey('InboxIsActive')) ``` ```javascript settings.objectForKey('InboxIsActive') //--> true settings.defaultObjectForKey('InboxIsActive') //--> true settings.boolForKey('InboxIsActive') //--> true settings.setBoolForKey(false, 'InboxIsActive') settings.boolForKey('InboxIsActive') //--> false ``` -------------------------------- ### Install OmniFocus Tutorial Project Source: https://omni-automation.com/omnifocus/tutorial/index.html This script checks if a project named 'OmniFocus Tutorial' exists. If not, it creates the project, adds tasks for each tutorial topic with corresponding URLs, and then opens the project. If the project already exists, it opens the existing project and shows an alert. ```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() } ``` -------------------------------- ### Get and Set Window Perspective Source: https://omni-automation.com/omnifocus/window.html Demonstrates how to get the current perspective object of an OmniFocus window and how to set it to a built-in perspective like '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 Object Reference for Tag by Name Source: https://omni-automation.com/omnifocus/tutorial/tag.html This snippet shows the basic pattern for getting an object reference to a tag by its name, creating the tag if it does not already exist. ```javascript var tagName = "name of tag" var tagObj = flattenedTags.byName(tagName) || new Tag(tagName) ``` -------------------------------- ### Get and Use DatabaseObject URL Source: https://omni-automation.com/omnifocus/database-object.html Retrieves the URL of a task and then uses the objectForURL function to get a reference to the task. Ensure the task exists before accessing its properties. ```javascript aTask = inbox[0] if (aTask){ taskURL = aTask.url //-> [object URL: omnifocus:///task/hX3u3oHdgEm] objectForURL(taskURL) //-> [object Task: Plan Party] } ``` -------------------------------- ### Get and Set Paragraph Default Tab Interval Source: https://omni-automation.com/omnifocus/style.html Demonstrates how to get and set the default tab interval for paragraphs in points. A value of 0.0 means no default interval. ```javascript styleInst.set(Style.Attribute.ParagraphDefaultTabInterval, 72) //-> true styleInst.get(Style.Attribute.ParagraphDefaultTabInterval) //-> 72 ``` -------------------------------- ### Create New Folder with Projects Source: https://omni-automation.com/omnifocus/project.html Create a new folder and then create multiple 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 Paragraph Tab Stops Source: https://omni-automation.com/omnifocus/style.html Use to get and set custom tab stops for a paragraph. The format is a comma-delimited string of positions and alignment types (L, R, C, D). ```javascript styleInst.get(Style.Attribute.ParagraphTabStops) //-> 28L,56L,84L,112L,140L,168L,196L,224L,252L,280L,308L,336L styleInst.set(Style.Attribute.ParagraphTabStops, '72L,144L,216R') styleInst.get(Style.Attribute.ParagraphTabStops) //-> 72L,144L,216R ``` -------------------------------- ### Create New Project with Tasks Source: https://omni-automation.com/omnifocus/project.html Create a new project and add tasks to it using the Project and Task constructors. ```javascript var project = new Project("My Top-Level Project") new Task("First Project Task", project) new Task("Second Project Task", project) ``` -------------------------------- ### Setup Script for Kanban Board Source: https://omni-automation.com/omnifocus/plug-in-kanban-board.html This script identifies or creates the main 'Kanban' tag and its associated category tags ('To Do', 'In Progress', 'Waiting', 'Done'). It then reorders these categories and opens them in OmniFocus. ```javascript (() => { const action = new PlugIn.Action(function(selection, sender){ // IDENTIFY KANBAN TAG, CREATE IF MISSING targetTag = flattenedTags.byName("Kanban") || new Tag("Kanban") // ADD KANBAN CATEGORIES IF MISSING tagTitles = ["To Do", "In Progress", "Waiting", "Done"] tagTitles.forEach(title => { if (!targetTag.children.byName(title)){ new Tag(title, targetTag) } }) // REORDER THE CATEGORIES tagTitles.forEach(title => { tag = targetTag.children.byName(title) moveTags([tag], targetTag) }) // SHOW THE TAGS tagIDs = targetTag.children.map(tag => tag.id.primaryKey) tagIDsString = tagIDs.join(",") URL.fromString("omnifocus:///tag/" + tagIDsString).open() }); return action; })(); ``` -------------------------------- ### Initialize and Get Note Attributes Source: https://omni-automation.com/omnifocus/plug-in-character-attributes.html This JavaScript code initializes the plug-in action, gets the selected OmniFocus item, and creates a virtual text object to access its current note attributes. ```javascript (() => { var action = new PlugIn.Action(async function(selection, sender){ try { var shouldLog = true if(shouldLog){console.clear()} var item = selection.databaseObjects[0] // CREATE VIRTUAL TEXT OBJECT CONTAING CURRENT NOTE var noteObj = new Text("", baseStyle) noteObj.replace(noteObj.range, item.noteText) var nStyle = noteObj.style // GET ATTRIBUTES RANGES var runRanges = noteObj.ranges(TextComponent.AttributeRuns) // CREATE FORM AND FORM ELEMENTS fontFamilyTitles = ["Default", "Avenir Next", "Baskerville", "Bodoni 72", "Bradley Hand", "Chalkboard SE", "Cochin", "Courier New", "Damascus", "Georgia", "Gill Sans", "Helvetica Neue", "Hoefler Text", "Menlo", "Noteworthy", "Optima", "Palatino", "Rockwell", "Savoye LET", "Snell Roundhand", "Times New Roman", "Trebuchet MS", "Verdana"] fontFamilyIndexes = fontFamilyTitles.map((title, index) => index) var fontFamCurVal = nStyle.get(Style.Attribute.FontFamily) fontFamCurVal = (fontFamCurVal === ".AppleSystemUIFont") ? "System Font":fontFamCurVal fontFamilyMenu = new Form.Field.Option( "fontFamily", `Font Family (${fontFamCurVal})`, fontFamilyIndexes, fontFamilyTitles, null ) fontFamilyMenu.allowsNull = true fontFamilyMenu.nullOptionTitle = "No Change" fntWghtCurVal = nStyle.get(Style.Attribute.FontWeight) fntWghtValueStrings = ["Default", "1", "2", "3", "4", "5", "6", "7", "8", "9"] fntWghtValues = fntWghtValueStrings.map((title, index) => index) fontWeightMenu = new Form.Field.Option( "fontWeight", `Font Weight (${fntWghtCurVal})`, fntWghtValues, fntWghtValueStrings, null ) fontWeightMenu.allowsNull = true fontWeightMenu.nullOptionTitle = "No Change" var fntSzeCurVal = nStyle.get(Style.Attribute.FontSize) fntSzeValueStrings = ["Default", "9", "10", "11", "12", "13", "14", "15", "16", "18", "24"] fntSzeValues = fntSzeValueStrings.map((title, index) => index) fontSizeMenu = new Form.Field.Option( "fontSize", `Font Size (${fntSzeCurVal})`, fntSzeValues, fntSzeValueStrings, null ) } catch(e) { console.error(e.message) } }); return action; })(); ``` -------------------------------- ### Plug-In Metadata and Initialization Source: https://omni-automation.com/omnifocus/plug-in-paragraph-attributes.html This snippet contains the plug-in's metadata, including its type, targets, author, identifier, version, and descriptive labels. It also includes the initialization code for the plug-in's action, setting up the environment to interact with OmniFocus tasks and their notes. ```javascript /*{ "type": "action", "targets": ["omnifocus"], "author": "Otto Automator", "identifier": "com.omni-automation.of.paragraph-attributes", "version": "1.4", "description": "This plug-in will display and apply the paragraph attribute settings of the note of the selected project or task.", "label": "Note Style Paragraph Attributes", "shortLabel": "Paragraph Attributes", "paletteLabel": "Paragraph Attributes", "image": "parkingsign.circle.fill" }*/ (() => { var action = new PlugIn.Action(async function(selection, sender){ try { var shouldLog = false if(shouldLog){console.clear()} var item = selection.databaseObjects[0] // CREATE VIRTUAL TEXT OBJECT CONTAING CURRENT NOTE var noteObj = new Text("", baseStyle) noteObj.replace(noteObj.range, item.noteText) var nStyle = noteObj.style // GET ATTRIBUTE RUN RANGES var runRanges = noteObj.ranges(TextComponent.AttributeRuns) // TEXT OBJECTS AND STYLE runRanges = noteObj.ranges(TextComponent.AttributeRuns) // CREATE FORM AND FORM ELEMENTS var txtAlgnCurVal = nStyle.get(Style.Attribute.ParagraphAlignment) var txtAlgnDsplyVal switch(String(txtAlgnCurVal)) { case "[object TextAlignment: Left]": txtAlgnDsplyVal = 'Left' break case "[object TextAlignment: Right]": txtAlgnDsplyVal = 'Right' break case "[object TextAlignment: Center]": txtAlgnDsplyVal = 'Center' break case "[object TextAlignment: Natural]": txtAlgnDsplyVal = 'Natural' break case "[object TextAlignment: Justified]": txtAlgnDsplyVal = 'Justified' break } paragraphAlignmentMenu = new Form.Field.Option( "paragraphAlignment", `Alignment (${txtAlgnDsplyVal})`, TextAlignment.all, null, null ) paragraphAlignmentMenu.allowsNull = true ``` -------------------------------- ### Create Project and Add Tags (Alphabetical Order) Source: https://omni-automation.com/omnifocus/project.html This script creates a new project and adds tags to it. The tags are sorted alphabetically by default. The script logs the tag titles and opens the project. ```javascript project = new Project("Colors of the Visible Light Spectrum") colors = ["Red", "Orange", "Yellow", "Green", "Cyan", "Blue", "Violet"] currentTags = flattenedTags colors.sort().forEach(color => { tag = currentTags.byName(color) || new Tag(color) project.task.addTag(tag) }) tagTitles = project.tags.map(tag => tag.name) console.log(tagTitles) URL.fromString("omnifocus:///task/" + project.id.primaryKey).open() ``` -------------------------------- ### Defer Task +1 Day Source: https://omni-automation.com/omnifocus/settings.html Increases the deferment date of the selected task by one day. If no defer date is set, it defaults to the start of the current day plus one day and a configured default start time. ```javascript /*{ "type": "action", "targets": ["omnifocus"], "author": "Otto Automator", "identifier": "com.omni-automation.of.defer-task-plus-one-day", "version": "1.1", "description": "This plug-in will increase the deferment of the selected task by one day.", "label": "Defer Task +1 Day", "shortLabel": "Defer Task +1d", "paletteLabel": "Defer Task +1d", "image": "24.square" }*/ (() => { const action = new PlugIn.Action(function(selection, sender){ // action code // selection options: tasks, projects, folders, tags, databaseObjects, allObjects task = selection.tasks[0] currentDeferDate = task.deferDate if (currentDeferDate){ dc = new DateComponents() dc.day = dc.day + 1 targetDate = Calendar.current.dateByAddingDateComponents(currentDeferDate, dc) task.deferDate = targetDate } else { startTime = settings.objectForKey('DefaultStartTime') //--> "00:00:00" timeElements = startTime.split(":") now = new Date() currentDeferDate = Calendar.current.startOfDay(now) dc = new DateComponents() dc.day = dc.day + 1 dc.hour = Number(timeElements[0]) dc.minutes = Number(timeElements[1]) dc.seconds = Number(timeElements[2]) targetDate = Calendar.current.dateByAddingDateComponents(currentDeferDate, dc) task.deferDate = targetDate } }); action.validate = function(selection, sender){ // validation code // selection options: tasks, projects, folders, tags, databaseObjects, allObjects return (selection.tasks.length === 1) }; return action; })(); ``` -------------------------------- ### Plug-in Metadata and Initialization Source: https://omni-automation.com/omnifocus/plug-in-show-latest-object.html Defines the plug-in's metadata, including its type, targets, author, identifier, version, and user-facing labels. It also initializes the main action with preferences for object type, date parameter, and spoken alerts. ```javascript /*{ "type": "action", "targets": ["omnifocus"], "author": "Otto Automator", "identifier": "com.omni-automation.of.show-latest-database-object", "version": "1.0", "description": "Shows the most recently added or modified active OmniFocus folder, project, task, or tag.", "label": "Show the Latest…", "shortLabel": "Show Latest…", "paletteLabel": "Show Latest…", "image": "1.magnifyingglass" }*/ (() => { var preferences = new Preferences() // NO ID = PLUG-IN ID function createUtterance(textToSpeak){ langCode = Speech.Voice.currentLanguageCode voiceObj = Speech.Voice.withLanguage(langCode) utterance = new Speech.Utterance(textToSpeak) utterance.voice = voiceObj utterance.rate = Speech.Utterance.defaultSpeechRate return utterance } const action = new PlugIn.Action(async function(selection, sender){ try { synthesizer = new Speech.Synthesizer() objectTypeIdx = preferences.readNumber("objectTypeIdx") if(!objectTypeIdx){ objectTypeIdx = 0 } console.log("objectTypeIdx", objectTypeIdx) objectType = ["Folder","Project","Task","Tag"] objectTypeMenu = new Form.Field.Option( "objectTypeIdx", "Object Type", [0,1,2,3], objectType, objectTypeIdx ) addedOrModifiedIdx = preferences.readNumber("addedOrModifiedIdx") if(!addedOrModifiedIdx){ addedOrModifiedIdx = 0 } console.log("addedOrModifiedIdx", addedOrModifiedIdx) searchParams = ["Added","Modified"] searchParamMenu = new Form.Field.Option( "addedOrModifiedIdx", "Date Parameter", [0,1], searchParams, addedOrModifiedIdx ) shouldSpeakAlert = preferences.readBoolean("shouldSpeakAlert") if(shouldSpeakAlert === null || shouldSpeakAlert === undefined){ shouldSpeakAlert = true } console.log("shouldSpeakAlert", shouldSpeakAlert) spokenAlertCheckbox = new Form.Field.Checkbox( "shouldSpeakAlert", "Use spoken result alert", shouldSpeakAlert ) inputForm = new Form() inputForm.addField(objectTypeMenu) inputForm.addField(searchParamMenu) inputForm.addField(spokenAlertCheckbox) formPrompt = "Search parameters:" buttonTitle = "Continue" formObject = await inputForm.show(formPrompt, buttonTitle) objectTypeIdx = formObject.values["objectTypeIdx"] preferences.write("objectTypeIdx", objectTypeIdx) objectTypeTerm = objectType[objectTypeIdx] console.log("Object Type:", objectType[objectTypeIdx]) addedOrModifiedIdx = formObject.values["addedOrModifiedIdx"] preferences.write("addedOrModifiedIdx", addedOrModifiedIdx) addedOrModifiedTerm = searchParams[addedOrModifiedIdx] console.log("Date Parameter:", searchParams[addedOrModifiedIdx]) shouldSpeakAlert = formObject.values["shouldSpeakAlert"] preferences.write("shouldSpeakAlert", shouldSpeakAlert) console.log("shouldSpeakAlert:", shouldSpeakAlert) switch (objectTypeIdx) { case 0: // FILTER FOLDERS var filteredObjects = flattenedFolders.filter(folder => { status = folder.status return (status === Folder.Status.Active) }) if(filteredObjects.length === 0){ throw { name: "Missing Object", message: "There are no active folders in the database." } } // SORT FOLDERS if(addedOrModifiedIdx === 0){ filteredObjects.sort((a, b) => b.added - a.added) } else { filteredObjects.sort((a, b) => b.modified - a.modified) } latestObject = filteredObjects[0] latestObject.url.open() break; case 1: // FILTER PROJECTS filteredObjects = flattenedProjects.filter(project => { status = project.status return (status === Project.Status.Active) }) if(filteredObjects.length === 0){ throw { name: "Missing Object", message: "There are no active projects in the database." } } // SORT PROJECTS if(addedOrModifiedIdx === 0){ filteredObjects.sort((a, b) => b.task.added - a.task.added) } else { filteredObjects.sort((a, b) => b.task.modified - a.task.modified) } latestObject = filteredObjects[0] latestObject.url.open() break; case 2: // FILTER TASKS filteredObjects = flattenedTasks.filter(task => { // AVOID ROOT TASKS OF PROJECTS if(task.containingProject !== null){ ``` -------------------------------- ### Get Document Name Source: https://omni-automation.com/omnifocus/big-picture.html Accesses the name of the current OmniFocus document. ```applescript document.name //--> "OmniFocus" ``` -------------------------------- ### Get All Tasks in Inbox Source: https://omni-automation.com/omnifocus/task.html Retrieves all tasks located in the Inbox. It iterates through the inbox and pushes each task into an array. ```javascript masterTaskArray = new Array() inbox.apply(task => masterTaskArray.push(task)) console.log(masterTaskArray) ``` -------------------------------- ### Retrieve Space After Value Source: https://omni-automation.com/omnifocus/plug-in-paragraph-attributes.html Gets the selected 'space after' value from the form and maps the indicator to its corresponding string. ```javascript spcAftIndicator = formObject.values["spaceAfter"] spcAftValue = spcAftValueStrings[spcAftIndicator] if(shouldLog){console.log("spcAftValue", spcAftValue)} ``` -------------------------------- ### Find Matching Tags Source: https://omni-automation.com/omnifocus/big-picture.html This example demonstrates how to use the `tagsMatching` function to find tags that 'smart match' a given search string. The results are returned in the same order as they would appear in the Quick Open window. ```javascript tagsMatching("Auto-") //--> [[object Tag: Auto-Open], [object Tag: Auto-Close], [object Tag: Auto-Update]] ``` -------------------------------- ### Plug-In Metadata and Main Action Source: https://omni-automation.com/omnifocus/plug-in-push-due-defer-dates-one-day.html This snippet contains the plug-in's metadata and the main JavaScript action. It handles advancing due and defer dates, includes preference dialogs for sound options, and plays a system alert upon completion on macOS. ```javascript /*{ "type": "action", "targets": ["omnifocus"], "author": "Otto Automator", "identifier": "com.omni-automation.of.push-due-defer-one-day", "version": "1.0", "description": "Advances the due and defer dates of the selected projects or tasks twenty-four hours. Items without due dates will use the default due time setting applied for tomorrow. Deferment time will be set to 12AM tomorrow for all selected items. TIP: Hold down Shift key when running plug-in to summon preferences dialog.", "label": "Push Due & Defer One Day", "shortLabel": "Push Due & Defer 24", "paletteLabel": "Push Due & Defer 24", "image": "24.circle" }*/ (() => { function playSystemAlert(alertFilename){ if(!alertFilename.endsWith(".aiff")){ alertFilename = alertFilename + ".aiff" } alertFilename = alertFilename.charAt(0).toUpperCase() + alertFilename.slice(1) sysSoundsFldr = URL.fromString("/System/Library/Sounds/") urlComps = URL.Components.fromURL(sysSoundsFldr, false) urlComps.path = alertFilename soundFileURL = urlComps.urlRelativeTo(sysSoundsFldr) audioAlert = new Audio.Alert(soundFileURL) Audio.playAlert(audioAlert) } var preferences = new Preferences() // NO ID = PLUG-IN ID var soundNames = ["Basso", "Blow", "Bottle", "Frog", "Funk", "Glass", "Hero", "Morse", "Ping", "Pop", "Purr", "Submarine", "Tink"] const action = new PlugIn.Action(async function(selection, sender){ try { storedBoolean = preferences.readBoolean("shouldPlaySound") if(storedBoolean === null){ preferences.write("shouldPlaySound", shouldPlaySound) var shouldPlaySound = false } else { var shouldPlaySound = storedBoolean } storedSoundIndx = preferences.readNumber("confirmationSoundIndx") if(storedSoundIndx === null){ preferences.write("confirmationSoundIndx", 10) var storedSoundIndx = 10 var confirmationSound = "Purr" } else { var confirmationSound = soundNames[storedSoundIndx] } if(app.shiftKeyDown){ checkSwitchField = new Form.Field.Checkbox( "shouldPlaySound", "Play sound after adjusting due and defer dates", shouldPlaySound ) soundsOptionsMenu = new Form.Field.Option( "confirmationSoundIndx", "Confirmation Sound", [0,1,2,3,4,5,6,7,8,9,10,11,12,13], soundNames, storedSoundIndx ) inputForm = new Form() inputForm.addField(soundsOptionsMenu) inputForm.addField(checkSwitchField) formPrompt = "Plug-in Options:" buttonTitle = "Continue" formObject = await inputForm.show(formPrompt, buttonTitle) booleanValue = formObject.values['shouldPlaySound'] preferences.write("shouldPlaySound", booleanValue) var shouldPlaySound = booleanValue indx = formObject.values['confirmationSoundIndx'] preferences.write("confirmationSoundIndx", indx) var confirmationSound = soundNames[indx] } // DEFERMENT DATE TIME = TOMORROW MORNING (12AM) now = new Date() today = Calendar.current.startOfDay(now) duration = new DateComponents() duration.day = 1 defermentDateTime = Calendar.current.dateByAddingDateComponents(today, duration) // DERIVE A DEFAULT DUE DATE/TIME FOR TOMORROW defaultDueTime = settings.objectForKey('DefaultDueTime') //--> "17:00:00" (5PM) console.log("DefaultDueTime", defaultDueTime) timeElements = defaultDueTime.split(":") dc = new DateComponents() dc.day = dc.day + 1 dc.hour = Number(timeElements[0]) dc.minutes = Number(timeElements[1]) dc.seconds = Number(timeElements[2]) defaultDueDate = Calendar.current.dateByAddingDateComponents(today, dc) // PROCESS THE SELECTED ITEMS selectedItems = selection.databaseObjects for (indx in selectedItems){ item = selectedItems[indx] if (item instanceof Project || item instanceof Task){ if(item.dueDate){ dc = Calendar.current.dateComponentsFromDate(item.dueDate) dc.hour = dc.hour + 24 newDueDate = Calendar.current.dateFromDateComponents(dc) item.dueDate = newDueDate } else { item.dueDate = defaultDueDate } // SET DEFERMENT item.deferDate = defermentDateTime } } if(shouldPlaySound && Device.current.mac){playSystemAlert(confirmationSound)} } catch(err){ if(!err.causedByUserCancelling){ console.error(err.name, err.message) new Alert(err.name, err.message).show() } } }); action.validate = function(selection, sender){ // selection options: tasks, projects, folders, tags, databaseObjects, allObjects ``` -------------------------------- ### Tag Ordering Source: https://omni-automation.com/omnifocus/project.html Demonstrates how to add and order tags for a project's root task. It shows adding tags in a specific sequence and opening the project to view the result. ```javascript project = new Project("Tag Ordering Example") tagRed = flattenedTags.byName("Red") || new Tag("Red") tagGreen = flattenedTags.byName("Green") || new Tag("Green") tagBlue = flattenedTags.byName("Blue") || new Tag("Blue") project.task.addTag(tagBlue) insertionLocation = project.task.beforeTag(tagBlue) project.task.addTag(tagGreen, insertionLocation) project.task.addTag(tagRed, project.task.beginningOfTags) id = project.id.primaryKey URL.fromString(`omnifocus:///task/${id}`).open() ``` -------------------------------- ### Close Document Window Source: https://omni-automation.com/omnifocus/window.html Closes the specified document window. Example usage: document.windows[0].close(). ```javascript document.windows[0].close() ``` -------------------------------- ### Get Titles of Selected Tasks Source: https://omni-automation.com/omnifocus/big-picture.html Retrieves the names (titles) of all tasks currently selected in the active OmniFocus window. ```applescript var selectedTasks = document.windows[0].selection.tasks taskTitles = selectedTasks.map(task => {return task.name}) ``` -------------------------------- ### Make and Show New Task Source: https://omni-automation.com/omnifocus/task.html Creates a new task, generates a URL to open it, and then opens that URL to display the task in the OmniFocus application. ```javascript task = new Task("My New Task", inbox.beginning) urlString = "omnifocus:///task/" + task.id.primaryKey URL.fromString(urlString).open() ``` -------------------------------- ### Retrieve References to All Tasks Source: https://omni-automation.com/omnifocus/task.html Gets object references to all tasks within the entire OmniFocus database using the flattenedTasks property. ```javascript flattenedTasks ``` -------------------------------- ### Get Names of Open OmniFocus Windows Source: https://omni-automation.com/omnifocus/window.html This script retrieves the names of all currently open OmniFocus windows by mapping their perspectives. ```javascript winNames = document.windows.map(win => win.perspective.name) ``` -------------------------------- ### Initialize Plug-in Variables and Read Credentials/Preferences Source: https://omni-automation.com/omnifocus/plug-in-replicate-task-in-hive.html Initializes plug-in variables like logging preference and service title, then reads existing Hive credentials and workspace ID from plug-in preferences. ```javascript var shouldLogToConsole = true var serviceTitle = "Hive" var credentials = new Credentials() var preferences = new Preferences() var action = new PlugIn.Action(async function(selection, sender){ var credentialsObj = credentials.read(serviceTitle) var workspaceID = preferences.readString("workspaceID") ``` -------------------------------- ### Retrieve Tail Indent Value Source: https://omni-automation.com/omnifocus/plug-in-paragraph-attributes.html Gets the selected tail indent value from the form and converts the indicator to its string representation. ```javascript tailIndentIndicator = formObject.values["tailIndent"] tailIndentValue = tailValueStrings[tailIndentIndicator] ``` -------------------------------- ### Select 1st Project with Specified Name Source: https://omni-automation.com/omnifocus/window.html Selects the first project matching a given name. Ensures the Projects perspective is active before selection. ```javascript var targetName = "Project A" var targetProject = flattenedProjects.byName(targetName) if(targetProject){ document.windows[0].perspective = Perspective.BuiltIn.Projects document.windows[0].selectObjects([targetProject]) } ``` -------------------------------- ### Configure and Display Map Form Source: https://omni-automation.com/omnifocus/plug-in-add-static-map.html This snippet demonstrates setting up a form with various map configuration options and displaying it to the user. It includes fields for map style, size, zoom, pin status, pin color, and high resolution. ```javascript pinColorValues = ["f00", "0f0", "0f0", "000", "fff", "808080", "a9a9a9", "d3d3d3"] pinColorIndexes = [0, 1, 2, 3, 4, 5, 6, 7] pinColorMenu = new Form.Field.Option( "pinColorIndex", "Pin Color", pinColorIndexes, pinColorTitles, pinColorIndex ) inputForm = new Form() inputForm.addField(mapStyleMenu) inputForm.addField(mapSizeMenu) inputForm.addField(mapZoomMenu) inputForm.addField(pinStatusCheckbox) inputForm.addField(pinColorMenu) inputForm.addField(highResCheckbox) inputForm.validate = function(formObject){ return true } formPrompt = "Select Mapbox map parameters:" buttonTitle = "Continue" // PRESENT FORM AND WAIT FOR RESULTS formObject = await inputForm.show(formPrompt, buttonTitle) ``` -------------------------------- ### Get Selected Tasks Source: https://omni-automation.com/omnifocus/task.html Retrieves object references to the currently selected tasks in OmniFocus. Returns an empty array if no tasks are selected. ```javascript document.windows[0].selection.tasks ``` -------------------------------- ### Create Sequential Project Source: https://omni-automation.com/omnifocus/project.html Creates a new project with sequential tasks. All tasks added to this project will be executed in order. ```javascript var project = new Project("My Project") project.sequential = true new Task("Task One", project) new Task("Task Two", project) new Task("Task Three", project) ``` -------------------------------- ### Retrieving All Tag Names with map Source: https://omni-automation.com/omnifocus/tag.html This script iterates through flattenedTags using map() to get the names of all tags in the database and logs them to the console. ```javascript tagNames = flattenedTags.map(tag => tag.name) console.log(tagNames) ``` -------------------------------- ### Get Projects of Selected Tag Source: https://omni-automation.com/omnifocus/tag.html Retrieves the projects associated with a single selected tag. If multiple tags are selected, this will return null. ```javascript var tgs = document.windows[0].selection.tags projects = (tgs.length === 1) ? tgs[0].projects : null ``` -------------------------------- ### Create New Sequential Project (Root Task) Source: https://omni-automation.com/omnifocus/project.html Alternatively, create a new sequential project by setting the 'sequential' property of the project's root task to true. ```javascript var project = new Project("Sequential Project") project.task.sequential = true ```