Quirky tab behavior with workflow


#1

It’s not really an issue, but I am curious — I use an Alfred workflow that runs a script to add a task to an inbox project. When I run the workflow, if I have multiple tabs open, the screen automatically switches to the next tab. Is there a way to stop this behavior?

Below is the script


// 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[-0]',
    filePath: '/Users/Jinora/Dropbox/TextFiles/To Do.taskpaper',
    textLines: query
});

#2

I’m not sure on the underlying cause in the code (or how hard it would be to work around), but I just tested, and the part of the script that causing this behavior is tp3.open(Path(strFullPath)).

You should be able to avoid that call if the document is already open in TaskPaper. Unfortunately I can’t off the top of my head tell you the syntax you need, but it would be something along the line of tp3.documents.whose.name.is(Path(strFullPath)).