Showing all tasks before running a search


#1

I’m hoping someone can help me out with an Alfred workflow. I am able to run a workflow that shows all of my tasks due within X days, and it works great, but it only shows the tasks within the last-selected project. I’m trying to figure out how to clear the selected project before running the search so that I see all tasks due in X days across all of the projects.

Thank you for any suggestions. I’m still struggling with the transition from Applescript to Javascript.


#2

Can you show us the .js which you are using at the moment ?

( We may just be able to fix that quickly for you )


#3

No problem – and thanks for responding – it is actually one from this forum that you had posted:

var alfredText = "- " + "{query}";

// SEND TEXT LINES TO INBOX: PROJECT OF FRONT TASKPAPER DOCUMENT

// Predraft version 0.02
// This version just gets its text from the clipboard
// Could be adapted for Keyboard Maestro, LaunchBar, Alfred etc

var a = Application.currentApplication(),
    sa = (a.includeStandardAdditions = true, a); 

// N.B. you need to give a filepath to an existing TaskPaper document
// in the:
// OPTIONS SETTINGS AT BOTTOM OF SCRIPT


(function (dctOptions) {
    'use strict';

    // TASKPAPER CONTEXT ***************************************

    function TaskPaperContext(editor, options) {

        // FIND OR MAKE A PROJECT TO HOLD INCOMING TEXT
        // String -> String -> {project: tpItem, new: Bool}
        function projectAtPath(strProjectPath, strDefaultName) {
            var strDefault = strDefaultName || 'Inbox:',
                outline = editor.outline,
                lstMatch = outline.evaluateItemPath(strProjectPath),
                blnFound = lstMatch.length > 0;

            return {
                project: blnFound ? lstMatch[0] : (function () {
                    var defaultProject = outline.createItem(
                        strDefault)

                    outline.groupUndoAndChanges(function () {
                        outline.root.appendChildren(
                            defaultProject
                        );
                    });

                    return defaultProject;
                })(),
                new: !blnFound
            };
        }

        // parsedLines :: String -> [{indent: Int, text:String, bulleted:Bool}]
        function parsedLines(strText) {
            var rgxLine = /^(\s*)([\-\*\+]*)(\s*)/;

            return strText.split(/[\n\r]+/)
                .map(function (x) {
                    var ms = rgxLine.exec(x);

                    return {
                        indent: (ms ? ms[1] : '')
                            .replace(/    /g, '\t')
                            .length,
                        text: x.slice((ms ? ms[0] : '')
                            .length),
                        bulleted: ms[2].length > 0
                    };
                });
        }


        // textNest :: [{indent:Int, text:String}, bulleted:Bool]
        //          -> Tree {text:String, nest:[Tree]}
        function textNest(xs) {
            var h = xs.length > 0 ? xs[0] : undefined,
                lstLevels = [{
                    text: undefined,
                    nest: []
            }];

            if (h) {
                var lngBase = h.indent;

                xs.forEach(function (x) {
                    var lngMax = lstLevels.length - 1,
                        lngLevel = x.indent - lngBase,
                        dctParent = lngLevel > lngMax ? lstLevels[
                            lngMax] : lstLevels[lngLevel],
                        dctNew = {
                            bullet: lngLevel === 0 || x.bulleted,
                            text: x.text,
                            nest: []
                        };

                    dctParent.nest.push(dctNew);

                    if (lngLevel > lngMax) lstLevels.push(dctNew);
                    else lstLevels[lngLevel + 1] = dctNew;
                });

            }
            return lstLevels[0];
        }

        // insertNest :: tp3Node ->
        //      Tree {text:String, nest:[Tree], bullet:Bool} -> ()
        function insertNest(oParent, oTextNest) {

            // placeSubNest :: tp3Node -> Tree {text:String, nest:[Tree], bullet:Bool} -> ()
            function placeSubNest(oParent, lstNest) {
                // IMMEDATE CHILD NODES CREATED, 
                if (lstNest.length > 0) {
                    var lstChiln = lstNest.map(function (dct) {
                        return outline.createItem((dct.bullet ?
                                '- ' : '') +
                            (dct.text || ''));
                    });

                    // AND PLACED UNDER EXISTING PARENT LINE
                    outline.groupUndoAndChanges(function () {
                        oParent.appendChildren(lstChiln);
                    });

                    // THEN RECURSION WITH EACH CHILD FOR 
                    // ITS DESCENDANTS, IF ANY
                    zipWith(function (dctNest, oNode) {
                        var lstSub = dctNest.nest;

                        if (lstSub.length > 0) {
                            placeSubNest(oNode, lstSub);
                        }
                    }, lstNest, lstChiln);
                }
            }

            // Ensure that the nest has a virtual root
            var outline = editor.outline;

            // Place the nest beneath the parent
            placeSubNest(oParent, oTextNest.nest)
        }

        // zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
        function zipWith(f, xs, ys) {
            var ny = ys.length;
            return (xs.length <= ny ? xs : xs.slice(0, ny))
                .map(function (x, i) {
                    return f(x, ys[i]);
                });
        }


        // TASKPAPER CONTEXT MAIN:

        // 1. FIND OR CREATE AN INBOX
        var outline = editor.outline,
            mInbox = projectAtPath(options.inboxPath, 'Inbox:'),
            itemInbox = mInbox.project;


        // 2. PARSE THE INCOMING TEXT TO A NEST
        var dctNest = textNest(
            parsedLines(
                options.textLines
            )
        );

        // 3. INSERT THE TEXT NEST IN THE INBOX
        insertNest(
            itemInbox,
            dctNest
        );

    }


    // JAVASCRIPT FOR AUTOMATION  CONTEXT ***********************

    // fileExists :: String -> Bool
    function fileExists(strPath) {
        var error = $();

        $.NSFileManager.defaultManager
            .attributesOfItemAtPathError(
                ObjC.unwrap($(strPath)
                    .stringByExpandingTildeInPath),
                error
            );

        return error.code === undefined;
    }


    //  JSA MAIN ***********************************************


    var a = Application.currentApplication(),
        sa = (a.includeStandardAdditions = true, a);


    //1. DOES THE FILE EXIST ?

    var strFullPath = ObjC.unwrap(
        $(dctOptions.filePath)
        .stringByExpandingTildeInPath
    );


    if (fileExists(strFullPath)) {
        var tp3 = Application("TaskPaper"),
            d = tp3.open(Path(strFullPath));

        //2. And an inbox in this file
        //3. and place the text

        if (d) {

            return d.evaluate({
                script: TaskPaperContext.toString(),
                withOptions: dctOptions
            });
        }

    } else {
        sa.activate();
        sa.displayDialog('File not found:\n\n' + strFullPath, {
            //defaultAnswer: undefined,
            //buttons : undefined,
            defaultButton: 'OK',
            //cancelButton : undefined,
            withTitle: "Quick entry",
            withIcon: sa.pathToResource('TaskPaperAppIcon.icns', {
                inBundle: 'Applications/TaskPaper.app'
            }), // 'note'
            givingUpAfter: 30
        })
    }
    
    // SCRIPT OPTIONS

})({
    inboxPath: '//Inbox and @type=project[-1]',
    filePath: '/Users/mattm/Library/Mobile Documents/com~apple~CloudDocs/Tasks/Tasks.taskpaper',
    textLines: alfredText
});

#4

It sounds like the itemPath you need may be something like:

'//@due <[d] now+' + options.days + 'd'

Depending on what you mean by ‘see’ all tasks (concatenated string ? array of strings ? array of records for further processing ?) you could harvest a list of things due within N days like this:

function run() {

    // TASKPAPER CONTEXT
    function TaskPaperContext(editor, options) {
        return editor
            .outline
            .evaluateItemPath('//@due <[d] now+' + options.days + 'd')
            .map(function (item) {
                return item.bodyString;
            });
    }


    // JAVASCRIPT FOR AUTOMATION CONTEXT
    var ds = Application('com.hogbaysoftware.TaskPaper3')
        .documents;

    if (ds.length) {
        return ds[0].evaluate({
            script: TaskPaperContext.toString(),
            withOptions: {
                days: 6
            }
        });
    }
}

In that form it would give you the list as an array

["- alpha @due(2016-05-07)", "- beta @due(now + 2d)", "- gamma @due(now + 3d)", 
"- delta @due(now + 4d)", "- epsilon @due(now + 5d)", "- zeta @due(2016-05-12)"]

and adding .join('\n')

would rewrite that as a text of \n delimited lines

    ...
            .map(function (item) {
                return item.bodyString;
            }).join('\n')

Notice that the value N, where N is a number of days, is coming in through the withOptions record/object


#5

And to clear a filter, you might write something like:

function run() {

    // TASKPAPER CONTEXT
    function TaskPaperContext(editor, options) {
        editor.itemPathFilter = '';
    }


    // JAVASCRIPT FOR AUTOMATION CONTEXT
    var ds = Application('com.hogbaysoftware.TaskPaper3')
        .documents;

    if (ds.length) {
        return ds[0].evaluate({
            script: TaskPaperContext.toString(),
            withOptions: {}
        });
    }
}

#6

Thank you! I will give this a try over the weekend.