How to duplicate a task in JXA - javascript for automation

I understand that I can learn Omnifocus Automation plugins etc. I will.

For now, can someone help me with how to create a duplicate of a task in the containing project of the task, and if it is an inbox task to create the task in inbox. I did search the web and the forum but there does not seem to be a way to do this using JXA - there are plugins.

In the code below, the questions are related to

  • the duplicate command - there is an error in how it is invoked
  • also, I understand that this will not work for inboxTasks and if there are ideas related to that it will be great

I reviewed this in the OmniFocus javascript dictionary, but unable to construct the right syntax.

duplicate method : Copy an object.
duplicate specifier or list of specifier : The object(s) to copy.
[to: location specifier] : The location for the new copy or copies.
[withProperties: record] : Properties to set in the new copy or copies right away.
→ specifier or list of specifier : the duplicated object(s)

Thank you!

(() => {
  "use strict";

  function main() {

    const OmniFocus = Application("OmniFocus");
    OmniFocus.includeStandardAdditions = true;

    // Get selected tasks in OmniFocus
    const frontDoc = OmniFocus.defaultDocument.documentWindows[0];
    const content = frontDoc.content();
    const selectedItems = content.selectedTrees.value();

    // onlyTasks :: [OF Item] -> [OF Task]
    const onlyTasks = (seln) =>
      seln.filter(
        (x) => ObjectSpecifier.classOf(x) == "task" ||
        ObjectSpecifier.classOf(x) == "inboxTask"
      );

    const tasksSelected = onlyTasks(selectedItems);
    if (tasksSelected.length === 0) {
      OmniFocus.displayDialog("You didn't select any OmniFocus tasks.");
      return; // Exit early if no selection
    }

    // Modify tasks in OmniFocus
    return tasksSelected.forEach((task) => {
      dupTaskProperties = {
        name: "waiting_on: " + task.name(),
        note: task.note(),
        dueDate: task.dueDate(),
        deferDate: task.deferDate(),
      };

      let duplicateTask = OmniFocus.duplicate(task, {
        to: task.containingProject,
        withProperties: dupTaskProperties,
      });
      // mark the task complete
      task.markComplete();

    });
  }

  return main();
})();

JXA duplicate OmniFocus command doesn’t work (we rarely are able to use location specifiers).

This should get you started; I created a custom duplicateTaskWith function. This example duplicates the selected task (no matter if it is in the inbox or not). Questions are welcomed:

(() => {
    "use strict";

	// Copyright (c) 2024 Gabriel Scalise
    // Twitter - @unlocked2412

    // jxaContext :: IO ()
    const jxaContext = () => {
        // main :: IO ()
        const main = () => {
            const
                ofApp = Application("OmniFocus"),
                doc = ofApp.defaultDocument,
                win = doc.documentWindows.at(0),
                content = win.content,
                seln = content.selectedTrees.at(0).value();

            return duplicateTaskWith(ofApp)({
                "name": "waiting_on: " + seln.name()
            })(seln)
        };

        // FUNCTIONS --
        // taskDict :: OF Task -> Dict
        const taskDict = task => ({
            "name": task.name(),
            "note": task.note(),
            "deferDate": task.deferDate(),
            "dueDate": task.dueDate()
        });

        // duplicateTaskWith :: Application -> Dict -> OF Task -> OF Task
        const duplicateTaskWith = app => dctProps => x => {
            const
                dct = Object.assign({},
                    taskDict(x), dctProps
                ),
                task = app.Task(dct),
                parent = x.parentTask();
            return parent === null ? (() => {
                return (
                    app
                    .defaultDocument
                    .inboxTasks
                    .push(task),
                    task
                )
            })() : (
                parent
                .tasks
                .push(task),
                task

            )
        };

        // MAIN --
        return main();
    };

    return jxaContext();
})();
2 Likes

Thank you for the code.
And for the insight that the duplicate command does not work.

Trying to learn from your code structuring style. Hopefully, my next script will be closer in structure.

You’re welcome. Do let me know if your are able to solve your end goal and you need more help or have more questions.

1 Like