As someone who is somewhat obsessed with automating OmniFocus, I naturally enjoyed this episode!
A couple of small points Iāve picked up on the Omni Slack channel that I thought might be useful to share:
1. Reducing items in share menu
@MacSparky mentioned the issue of an overpopulated āshareā menu in creating his template script. One potential solution to this is to update the validation function so that it is not available when a task or project is selected, something like this:
action.validate = (selection, sender) => {
return selection.tasks.length === 0 && selection.projects.length === 0
}
This way it doesnāt show on the share sheet, but can still be run from the Automation menu or via keyboard shortcut. The trade-off with this is that, obviously, if something is selected, it wonāt be available! I usually get around this by just clicking somewhere else, but it might be a dealbreaker for some.
2. Running actions automatically (and in the background) using Keyboard Maestro
There was also some discussion about running actions automatically, or on a schedule. Previously I had been doing this using a Keyboard Maestro action that called a URL (as I think was discussed on the show) but the downside to this was that it drew focus to the OmniFocus each time. Just in the last couple of days Ken Case pointed out in the Slack channel that a script can be run via AppleScript, one benefit of which is that this can happen in the background which is much nicer. So now my Keyboard Maestro macros are just a single āExecute AppleScriptā action that looks something like:
tell application "OmniFocus"
evaluate javascript "PlugIn.find('com.KaitlinSalzke.Scheduling').action('newDay').perform()"
end tell
(As an aside, I was amused to hear the comment about how everyone had their own Template script. I also have one in progress )
This is actually the original method behind my Auto-Parser script. It was all AppleScript so it could be run with Hazel or a handful of other automation tools. The trick is mimicking that feature on iOS.
This is the problem with templating. Everyone wants it in a different way.
Iām in bed waiting for the baby to wake up and decide to feed, so I havenāt tested, butā¦in the absence of a better option, I wonder whether an āOn App Openā trigger in Shortcuts that runs the script via a URL might work somewhat effectively for the parsing script? (It might jump around a bit, though, which might be annoying. Iām not sure.)
Enjoyed the episode. Any ideas on best way to create a shortcut to run a omnifocus plug-in that i can keep in a widget on my home screen.
Great episode, have really enjoyed playing with the JS automation in OmniFocus. For anyone who missed it I wrote a plugin that starts task timers in Toggl, it shows how you can use this to interact with other services out there to get the perfect setup your heart desires. (and avoid doing real work )
In the episode all three folks discussed using templates to automate creation of Projects in OmniFocus. Iāve been doing this with Drafts and would like to move it to OmniFocus Automation.
My question is how do I point the automation at a specific Taskpaper file rather than use a FilePicker
object?
It would. Thatās the trouble. Iāve not found any scripts on iOS that truly run in the background.
For the sake of keeping everything together:
Iām pretty sure you can bypass the FilePicker
, but itāll be messy and platform dependent. The file system differences will change where it lives.
For example, using Omni JS on my Mac, a FilePicker
url looks like this:
file:///Users/joebuhlig/Documents/omnifocus/templates/article.txt
That same file, but on iOS:
file:///private/var/mobile/Library/Mobile%20Documents/com~apple~CloudDocs/Documents/omnifocus/templates/article.txt
Regardless, you should be able to change line 20.
Original: var fileURL = urlsArray[0]
Replace with: URL.fromString("file:///Users/joebuhlig/Documents/omnifocus/templates/article.txt");
Iām pretty sure you can bypass the
FilePicker
, but itāll be messy and platform dependent. The file system differences will change where it lives.For example, using Omni JS on my Mac, a
FilePicker
url looks like this:
file:///Users/joebuhlig/Documents/omnifocus/templates/article.txt
That same file, but on iOS:
file:///private/var/mobile/Library/Mobile%20Documents/com~apple~CloudDocs/Documents/omnifocus/templates/article.txt
Regardless, you should be able to change line 20.
Original:
var fileURL = urlsArray[0]
Replace with:
URL.fromString("file:///Users/joebuhlig/Documents/omnifocus/templates/article.txt");
Thanks, @joebuhlig !
Here is my code:
/*{
"author": "Dean Pribetic",
"targets": ["omnifocus"],
"type": "action",
"identifier": "co.findmethod.of-new--engagement",
"version": "0.1",
"description": "A plug-in that...",
"label": "New Engagement",
"mediumLabel": "of-new--engagement",
"paletteLabel": "of-new--engagement",
}*/
(() => {
var action = new PlugIn.Action(function(selection) {
var templateURL = URL.fromString("file:///Users/dean/Downloads/testFile.txt");
templateURL.fetch(data => {
console.log("Run!")
/*
var TaskPaperText = data.toString();
TaskPaperText = encodeURIcomponent(TaskPaperText);
var ofURL = "omnifocus:///paste?content=" + TaskPaperText;
URL.fromString(ofURL).open();
*/
});
});
// If needed, uncomment, and add a function that returns true if the current selection is appropriate for the action.
action.validate = function(selection, sender){
return true;
};
return action;
})();
When I trigger the automation it never gets to the console.log("Run!")
commandā¦which suggests itās not fetching the data.
In this case, you need to act on the Promise that is returned. Like so:
/*{
"author": "Dean Pribetic",
"targets": ["omnifocus"],
"type": "action",
"identifier": "co.findmethod.of-new--engagement",
"version": "0.1",
"description": "A plug-in that...",
"label": "New Engagement",
"mediumLabel": "of-new--engagement",
"paletteLabel": "of-new--engagement",
}*/
(() => {
var action = new PlugIn.Action(function(selection) {
var request = URL.FetchRequest.fromString("file:///Users/joebuhlig/Documents/omnifocus/templates/article.txt");
var templateFetch = request.fetch().then(function(data){
console.log("Run!")
/*
var TaskPaperText = data.toString();
TaskPaperText = encodeURIcomponent(TaskPaperText);
var ofURL = "omnifocus:///paste?content=" + TaskPaperText;
URL.fromString(ofURL).open();
*/
});
templateFetch.catch(error => {
console.log(error);
})
});
// If needed, uncomment, and add a function that returns true if the current selection is appropriate for the action.
action.validate = function(selection, sender){
return true;
};
return action;
})();
The trouble here becomes a permissions issue⦠I think. It gives me an error kCFErrorDomainCFNetwork error 1
Havenāt found the answer to that, but it seems to be grabbing the file correctly. Just not able to open it.
Hey @joebuhlig ā thanks for that. Iām getting the same thing with the errorā¦but it is definitely progress! Iāve looked up that error and most of the solutions about Safari and local storage.
The next thing Iām going to try is to put the templates into a Plug-In file and see if that gets me anywhere (it would also solve the iOS vs macOS issue).
Hi,
Iām trying to add in another line to this wonderful javascript plugin āComplete and Await Replyā that will add a tag to the task āwaitingā. I canāt seem to figure out how to do this⦠sigh.
Can someone help?
Hereās the code of he plugin
/*{
"author": "Rosemary Orchard",
"targets": ["omnifocus"],
"type": "action",
"identifier": "com.rosemaryorchard.omnifocus.complete-and-await-reply",
"version": "1.0",
"description": "Mark the currently selected task as complete and add a new task to await the reply.",
"label": "Complete and Await Reply",
"mediumLabel": "Complete and Await Reply",
"paletteLabel": "Complete and Await Reply",
}*/
(() => {
let action = new PlugIn.Action(function(selection) {
let duplicatedTasks = new Array()
selection.tasks.forEach(function(task){
insertionLocation = task.containingProject
if(insertionLocation === null){insertionLocation = inbox.ending}
dupTasks = duplicateTasks([task], insertionLocation)
dupTasks[0].name = "Waiting on reply: " + task.name;
duplicatedTasks.push(dupTasks[0].id.primaryKey);
task.markComplete();
});
idStr = duplicatedTasks.join(",")
URL.fromString("omnifocus:///task/" + idStr).open()
});
action.validate = function(selection){
return (selection.tasks.length >= 1)
};
return action;
})();
As per the install page:
This script does not add a waiting tag to the new task, but that could be added after line 19 with
dupTasks[0].addTag(tagNamed('Waiting On'));
(this assumes your tag is called āWaiting Onā placed at the top-level of tags).
Thanks very much! I had installed it a while ago and hadnāt seen that helpful note. So thanks both for the note and the helpful pointer!
Hey @joebuhlig. A quick update. I went down the plug-in path and it was the right choice. I can get the URL of the file via something like this (from Omni Automation)
var plugin = PlugIn.find("com.omni-automation.og.example-plug-in")
var resourceName = "fileName.taskpaper"
var aURL = plugin.resourceNamed(resourceName)
ā¦and then use the callback aUrl.fetch(function(data) {});
construct.
Thanks for all your help with this.