How do I "Focus In" in JavaScript (or detect if the outline is already focused in)?

I have a JavaScript that moves to the next next item, if the outline is already focused in.

How do I detect if the outline is focused in or not?

And if it is not, what is the best way to execute the “Focus In” command?

Do I select the menu item? (Outline > Focus In)
Or simulate a Keyboard shortcut? ⌘⌥→

Here is the current script, which works well, if I trigger it after the outline is focused in:

function TaskPaperContext(editor, options) {
    if (editor.focusedItem.nextItem) {
  editor.focusedItem = editor.focusedItem.nextItem
 }
}

Application('TaskPaper').documents[0].evaluate({
  script: TaskPaperContext.toString()
});

This might be closer to what you want:

function TaskPaperContext(editor, options) {
    if (editor.focusedItem == null) {
	  editor.focusedItem = editor.outline.items[0]
	} else if (editor.focusedItem.nextBranch) {
	  editor.focusedItem = editor.focusedItem.nextBranch
 	}
}

Application('TaskPaper').documents[0].evaluate({
  script: TaskPaperContext.toString()
});

If the editor is not focused in then the editor.focusedItem will == null.

1 Like

Thank you @jessegrosjean !

Your version helped me! I made one minor change, as I want to focus in on the next item, rather than the branch.

This is working in my tests thus far:

function TaskPaperContext(editor, options) {
    if (editor.focusedItem == null) {
	  editor.focusedItem = editor.outline.items[0]
	} else if (editor.focusedItem.nextBranch) {
	  editor.focusedItem = editor.focusedItem.nextItem
 	}
}

Application('TaskPaper').documents[0].evaluate({
  script: TaskPaperContext.toString()
});

Color me very happy! Thank you so much!

Added to wiki. This is the title I came up with, but I honestly didn’t like it, “Move to the next item while making sure the outline is in focus”

Not sure about the title, but you can modify it to make clear what it accomplishes.

1 Like

Hi @Victor — thanks for the wiki care!

I call it my Weekly Review script. But that might not help others when browsing the wiki.

I use this script for my GTD Weekly Review. The Weekly Review is part of the Getting Things Done productivity practice.

I use the script to focus in on each individual line in my TaskPaper document, so that I can review each one individually (making changes, adding tags, start/due dates, etc.).

This script (now) allows me to move from the reviewed item to the next item flawlessly. I am so happy!

An example:

1 Like

Nice approach : -)

Here, FWIW is a variation of your script which aims to skip any blank lines.
(My files seem to be full of them)

Expand disclosure triangle to view JS Source
(() => {
    "use strict";

    // Move focus to next non-empty line in file.
    // Starts with selected line, if there is no focus.

    // (Focus cleared if no more lines remain)

    // Rob Trew @2021
    // Ver 0.04

    // ------------------- JXA CONTEXT -------------------
    const main = () => {
        const docs = Application("TaskPaper").documents;

        return 0 < docs.length ? (
            docs.at(0).evaluate({
                script: `${TaskPaperContext}`
            })
        ) : "No documents open in TaskPaper";
    };

    // ---------------- TASKPAPER CONTEXT ----------------
    const TaskPaperContext = editor => {
        const tp3Main = () => (
            editor.focusedItem = (
                null === editor.focusedItem ? (
                    editor.selection.startItem
                ) : Boolean(editor.focusedItem.nextBranch) ? (
                    nextNonEmpty(
                        editor.focusedItem
                    )
                ) : null
            ),
            editor.focusedItem ? (
                editor.focusedItem.bodyContentString
            ) : ""
        );

        // ------------- NEXT NON-EMPTY LINE -------------

        // nextNonEmpty :: Item -> Item
        const nextNonEmpty = item =>
            until(
                x => Boolean(x.bodyString.trim()) || (
                    null === x.nextItem
                )
            )(
                x => x.nextItem
            )(
                item.nextItem
            );

        // ------------------- GENERIC -------------------
        // until :: (a -> Bool) -> (a -> a) -> a -> a
        const until = p =>
            // The value resulting from repeated applications
            // of f to the seed value x, terminating when
            // that result returns true for the predicate p.
            f => x => {
                let v = x;

                while (!p(v)) {
                    v = f(v);
                }

                return v;
            };

        return tp3Main();
    };

    // MAIN ---
    return main();
})();
1 Like

(Slightly updated now, above, to ver 0.02,
which simply clears the focus when no more lines remain)

1 Like

Good point @complexpoint — I don’t have blank lines in my lists, so I don’t test for them. Worth doing, as others may use blank lines.