Scripting question: changing @due to @today if the date is today

I’m trying to put together a script that will add @today to anything tagged @due with today’s date (ex: @due(2016-03-02).)

Below is a modified version of Jesse’s script for replacing @tomorrow with @today. With this script, a @today tag is only added to items that are tagged with both @due and @q (a random test tag).

function TaskPaperContextScript(editor, options) {
var today = DateTime.format(‘today’);
var outline = editor.outline;
outline.groupUndoAndChanges(function() {
outline.evaluateItemPath(’//@due’).forEach(function (each) {
each.setAttribute(‘data-today’, each.getAttribute(‘data-q’));
});
});
}

Application(“TaskPaper”).documents[0].evaluate({
script: TaskPaperContextScript.toString()
})

But when I replace

 each.setAttribute('data-today', each.getAttribute('data-q'));

with

  each.setAttribute('data-today', each.getAttribute('data-due', today));

Everything that’s tagged @due gets a @today tag added. Additionally, @due(2016-03-02) gets @today(2016-03-02), but @due just gets @today.

What should I be changing to only tag items that are due today?

Everything that’s tagged @due gets a @today tag added

The .forEach process is working through a list defined by the itemPath //@due

The trick will be to construct an item path that evaluates to a shorter list – only the items that you want to affect.

You can experiment in TaskPaper, referring to http://guide.taskpaper.com/formatting_dates.html, to get the itemPath filter that you want to use. Might, for example, be some variant of:

@due <=[d] tomorrow
function TaskPaperContextScript(editor, options) {
    var today = DateTime.format('today');
    var outline = editor.outline;
    
    outline.groupUndoAndChanges(function () {
        outline.evaluateItemPath('//@due < [d] tomorrow')
            .forEach(function (each) {
                each.setAttribute(
                    'data-today',
                    each.getAttribute('data-q')
                );
            });
    });
}

Application("TaskPaper")
    .documents[0].evaluate({
        script: TaskPaperContextScript.toString()
    })

Footnote: you can display code snippets on this forum with syntax highlighting if you precede and follow them with three back-tick characters.

```

code here

```

Details of ‘fenced code blocks’ at:

https://help.github.com/articles/creating-and-highlighting-code-blocks/#fenced-code-blocks

2 Likes

Thanks! What’s the purpose of the each.getAttribute ?

When I do

      each.setAttribute('data-today', each.getAttribute('data-due'));

I get

When I do

      each.setAttribute('data-today', each.getAttribute('data-testing'));

I get

And when I do

      each.setAttribute('data-today', each.getAttribute('data-today'));

or just

      each.setAttribute('data-today');

nothing happens.

(This is both a legitimate question and an excuse to abuse the code display trick. Thanks for sharing that!)

1 Like

The each in that expression is the TaskPaper item/line which the ‘.forEach’ process is currently looking at.

If we look at the list of ‘methods’ (or functions) available for items in:

http://guide.taskpaper.com/Item.html

We can click on .setAttribute(name, value)

and read:

The statement:

each.setAttribute('data-today', each.getAttribute('data-due'));

is doing two things:

  1. it’s giving a @today tag to that line (if it hasn’t already got one)
  2. it’s putting some value between the parentheses of that tag, in the pattern @today(someValue)

How is it choosing or deriving that value ?

It’s using item.getAttribute to read a value from the same item’s @due(someValue) tag.

(Whatever value is found between (or ‘got from’)the parentheses of the @due( … ) tag will be placed between those of the @today( …) tag)

1 Like

Okay, that’s what I thought it was doing, but I was confused since removing it made the script not work at all. Then I took a look at another script you posted and realized in order to add the today tag with no parentheses, I had to do

      each.setAttribute('data-tomorrow', '');

Thanks for holding my hand through this! :panda_face: I really appreciate the time you’ve taken to explain everything.

2 Likes

Also the complete fixed script for anyone who just wants to copy/paste something that works.

function TaskPaperContextScript(editor, options) {
    var today = DateTime.format('today');
    var outline = editor.outline;
    
    outline.groupUndoAndChanges(function () {
        outline.evaluateItemPath('//@due <= [d] tomorrow')
            .forEach(function (each) {
                each.setAttribute(
                    'data-today', ''
                );
            });
    });
}

Application("TaskPaper")
    .documents[0].evaluate({
        script: TaskPaperContextScript.toString()
    })

Hi. I belong to those who when it comes to javascript can’t hope for anything better than to copy/paste something that works. Thank you for the script! I have used it to create overdue and available tags as well. Three different scripts. Now, I was wondering if one could merge them into one script that would make sure that the item only has one of these tags. Any help is greatly appreciated

You might have to spell out the logic of which tag(s) get thrown out of the balloon when multiples are found.

For example an ordering like:

@available -> @due -> @today -> @overdue ?

in which any predecessors of the latest type of tag are considered redundant and get pruned out ?

Or something with a few more special cases ? (Is @available, for example, incompatible with @due, or can those two co-exist in your scheme ?)

PS if its essentially a 3 or 4 colour traffic light scheme, in which each type of tag has a higher temperature than its predecessor, then perhaps you could have a pair of key strokes:

  • add heat (switch to next (hotter) tag type)
  • reduce heat (switch back to previous (cooler) tag type).

(Perhaps with a base key and a shifted version ?)

1 Like

Ah yes, of course. I’m thinking, for now, that only those three tags are incompatible with one another, with @overdue at the top (hottest, >@due date), followed by @today (= @due date), and @available (>= @start date) last. As you put it, but without the @due:

@available -> @today -> @overdue

where the predecessors get pruned out.

The @due and @start tags, together with @flag can live beside any other tag. But perhaps @start could be added to list above, as the coldest tag, before @available

(Actually, I’m not sure about this scheme, and should have perhaps thought it over more thoroughly before asking for help.)

No problem – take your time – thinking about sketching a script is always a good way to experiment and tease out a bit more clarity.

You could experiment, if you like, with the following settings:

{ 
  // OPTIONS:
  // Rank tags and values cool -> hot (left -> right)
	
    tagOrder: ['available', 'today', 'overdue'],
    valueOrder: [], // value list can be empty, for simple tags
    forward: true, // create another copy of the script for moving back (edit to `forward: false`)
    cycle: true // Extremes cycle back to start ? (edit to `cycle: false` to stop at extremes)
}

at the bottom of this script:

Great! This looks very useful. Thank you very much!
I began experimenting a little with the script found in this thread:

1 Like