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


#1

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?


#2

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


#3

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!)


#4

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)


#5

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.


#6

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()
    })

#7

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


#8

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 ?)


#9

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.)


#10

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


#11

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:


#12

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