Deferring multiple Items by +1


#1

I’ve searched here and in the docs; but can’t find how to add (in Dates on the right hand side) 1 day (or 1 week, or 1 month) to multiple Items in such a way that the existing (Due and/or Defer - it makes no difference) dates are respected.

IOW, I have a SAL Project with items due on (or deferred until) June 1, June 2, June 3, June 4 etc until June 10. Ten sequenced events; each one day later than the previous.

How do I add, let’s say, 1 day to all of them respectively, in sequence, so that they now become due on (or deferred until) June 2, June 3, June 4, June 5 etc until June 11th?

When I use the +1 Day button on (all the Events in) such a selection (where the first Event is due on (or deferred until) June 1), they all become due on or deferred until June 2.

Not what I want.

Am I missing something, please?

Thanks!


#2

I’m not an Applescript expert but I’m guessing you’ll need a script that will go through each task and defer it to the current defer date plus 1 day.

It’s not something that’s automatically built-in.


#3

Thanks, Wilson - I’ll also email Omni support :-)


#4

Here’s a Javascript for Automation script from the awesome @unlocked2412 I am using successfully on macOS 10.14.5 with OmniFocus 3.3.2 Pro. It respects the dates of all selected tasks and will set due forward (or backward) relative to the current due date of each. The link above takes you to his original post in this forum. The code below is for posterity in case the other thread gets archived.

"use strict";

(function() {
  "use strict";

  // unlocked2412
  // Delay due dates of selected tasks

  // GENERIC FUNCTIONS

  // Left :: a -> Either a b

  var Left = function Left(x) {
    return {
      type: "Either",
      Left: x
    };
  };

  // Right :: b -> Either a b
  var Right = function Right(x) {
    return {
      type: "Either",
      Right: x
    };
  };

  // bindEither (>>=) :: Either a -> (a -> Either b) -> Either b
  var bindEither = function bindEither(m, mf) {
    return m.Right !== undefined ? mf(m.Right) : m;
  };

  // dialogChoice :: String -> String -> String ->
  //  [String] -> String -> String -> Int -> FilePath -> Either String Dict
  var dialogChoice = function dialogChoice(
    strTitle,
    strMsg,
    strDefault,
    lstButtons,
    strDefaultButton,
    strCancelButton,
    intMaxSeconds,
    strIconPath
  ) {
    var se = Application("System Events"),
      sa = ((se.includeStandardAdditions = true), se);
    try {
      sa.activate;
      return (function() {
        var dct = sa.displayDialog(
          strMsg,
          Object.assign(
            {
              buttons: lstButtons || ["Cancel", "OK"],
              defaultButton: strDefaultButton || "OK",
              cancelButton: strCancelButton || "Cancel",
              withTitle: strTitle,
              givingUpAfter: intMaxSeconds || 120
            },
            typeof strDefault === "string"
              ? {
                  defaultAnswer: strDefault
                }
              : {},
            typeof strIconPath === "string"
              ? {
                  withIcon: Path(strIconPath)
                }
              : {}
          )
        );
        return dct.gaveUp
          ? Left("Dialog timed out after " + intMaxSeconds + " seconds")
          : Right(dct);
      })();
    } catch (e) {
      return Left(e.message);
    }
  };

  // filter :: (a -> Bool) -> [a] -> [a]
  var filter = function filter(f, xs) {
    return xs.filter(f);
  };

  // isLeft :: Either a b -> Bool
  var isLeft = function isLeft(lr) {
    return lr.type === "Either" && lr.Left !== undefined;
  };

  // map :: (a -> b) -> [a] -> [b]
  var map = function map(f, xs) {
    return xs.map(f);
  };

  // ----

  var calculateDays = function calculateDays(theDate, int) {
    var oDate = new Date(theDate);
    return oDate.setDate(oDate.getDate() + int), oDate;
  };

  var of = Application("OmniFocus"),
    ds = of.documents,
    lrTasks = bindEither(
      bindEither(
        ds.length > 0 // Wrapped value
          ? Right(ds[0].documentWindows)
          : Left("No docs open"),
        function(dws) {
          return dws.length > 0 ? Right(dws[0]) : Left("No wins");
        }
      ),
      function(dw) {
        var classOf = ObjectSpecifier.classOf,
          ts = filter(function(x) {
            return classOf(x) === "task" || classOf(x) === "inboxTask";
          }, dw.content.selectedTrees.value());
        return ts.length > 0 ? Right(ts) : Left("No sel tasks");
      }
    );

  return isLeft(lrTasks)
    ? lrTasks.Left
    : (function() {
        var choice = dialogChoice(
          "Delay due dates of selected tasks",
          "Enter positive or negative numbers",
          "1"
        );
        return isLeft(choice)
          ? choice.Left
          : (function() {
              return !Number.isNaN(choice.Right)
                ? map(
                    function(x) {
                      return (x.dueDate = calculateDays(
                        x.dueDate(),
                        parseInt(choice.Right.textReturned)
                      ));
                    },
                    filter(function(x) {
                      return x.dueDate() !== null;
                    }, lrTasks.Right)
                  )
                : Left("Please, enter a number");
            })();
      })();
})();

#5

Thanks so much, @TheWart

I’ll see if I can get that working and maybe do the trick.

I also got a reply from the ever-helpful Christian at OG. He suggested ‘Defer’ here :-)

Thanks again!