How do I indent every other line in this JavaScript?

Hello all!

I am using a JavaScript that creates a specific project and tasks. I use this daily, to set up my regular practice sessions.

I want to indent every other line as a child, but my attempted use of \t is not working.

Currently, the script creates:

— Practice Sessions → 1/9:
	- Session A → 6:30—7:30 → Cards → 
	- Practice 1
	- Session B → 8:30—9:30 → Coins → 
	- Practice 2
	- Session C → 10:30—11:30 → Sleight-of-Hand → 
	- Practice 3

But I want it to be this:

— Practice Sessions → 1/9:
	- Session A → 6:30—7:30 → Cards → 
		- Practice 1
	- Session B → 8:30—9:30 → Coins → 
		- Practice 2
	- Session C → 10:30—11:30 → Sleight-of-Hand → 
		- Practice 3

Any ideas on how to do this?

The script:

function TaskPaperContext(editor, options) {
const d = new Date();
const dtd = d.getMonth() + 1 + "/" + (d.getDate() + 1);
    let outline = editor.outline
    let project = outline.createItem('— Practice Sessions → ' + dtd + ":")
    project.appendChildren([
        outline.createItem('- Session A → 6:30—7:30 → Cards → '),
        outline.createItem('- Practice 1'),
        outline.createItem('- Session B → 8:30—9:30 → Coins → '),
        outline.createItem('- Practice 2'),
        outline.createItem('- Session C → 10:30—11:30 → Sleight-of-Hand → '),
        outline.createItem('- Practice 3')
    ])
    let now = editor.outline.evaluateItemPath('project Now:')[0]
    now.parent.insertChildrenBefore(project, now)
    editor.moveSelectionToItems(project, 0, project, 0)
}

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

I think you need to build up the structure like this (note multiple calls to appendChildren instead of just one):

let sessionA = outline.createItem('- Session A → 6:30—7:30 → Gaming → ')
sessionA.appendChildren(outline.createItem('- Practice 1'))

let sessionB = outline.createItem('- Session B → 8:30—9:30 → TP Top Three → ')
sessionB.appendChildren(outline.createItem('- Practice 2'))

let project = outline.createItem('— Practice Sessions → ' + dtd + ":")
project.appendChildren([
	sessionA,
	sessionB
])
1 Like

You nailed it @jessegrosjean !

Thank you ever so much!

On the chance that this will help someone in the future, here is the completed script:

function TaskPaperContext(editor, options) {
const d = new Date();
const dtd = d.getMonth() + 1 + "/" + (d.getDate() + 1);
    let outline = editor.outline
let sessionA = outline.createItem('- Session A → 6:30—7:30 → Cards → ')
sessionA.appendChildren(outline.createItem('- Practice 1'))

let sessionB = outline.createItem('- Session B → 8:30—9:30 → Coins → ')
sessionB.appendChildren(outline.createItem('- Practice 2'))

let sessionC = outline.createItem('- Session C → 10:30—11:30 → Sleight-of-Hand → ')
sessionC.appendChildren(outline.createItem('- Practice 3'))

let project = outline.createItem('— Practice Sessions → ' + dtd + ":")
project.appendChildren([
	sessionA,
	sessionB,
	sessionC
])
    let now = editor.outline.evaluateItemPath('project Now:')[0]
    now.parent.insertChildrenBefore(project, now)
    editor.moveSelectionToItems(project, 0, project, 0)
}

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

I should note that it adds the date for the next day (as I prepare the tasks the night before), and it places the project before a project named Now. You will have to edit that to be one of your own projects.

I hope that helps!

FWIW if you had various outlines of this kind, or wanted to reduce the effort of refactoring them when needs change, you could reduce the pattern to a general function like:

const newParentWithChildren = txt =>
    children => {
        const parent = outline.createItem(txt);

        parent.appendChildren(children);

        return parent;
    };

which can be applied over a nested list by a generic helper function (foldTree)

Expand disclosure triangle to view foldTree
const foldTree = f => {
    // A general bottom-up fold over a tree
    // connecting each node to the result of a
    // map over its children.
    const go = tree => f(
        tree[0]
    )(
        tree[1].map(go)
    );

    return go;
};

The nested list format used there represents any node in the outline as a pair (list of two items) like ["text", []]

where:

  • the first item is the node text
  • the second item is a list of any children (or an empty [] if there are no children), in the same format.

so here, for example:

const
    d = new Date(),
    nextMonth = 1 + d.getMonth(),
    nextDay = 1 + d.getDate(),
    dtd = `${nextMonth}/${nextDay}`;

const nesting = [
    `Practice Sessions → ${dtd}:`,
    [
        [
            "Session A → 6:30—7:30 → Cards →",
            [
                ["Practice 1", []]
            ]
        ],
        [
            "Session B → 8:30—9:30 → Coins →",
            [
                ["Practice 2", []]
            ]
        ],
        [
            "Session C → 10:30—11:30 → Sleight-of-Hand →",
            [
                ["Practice 3", []]
            ]
        ]
    ]
];
Expand disclosure triangle to view a working JS example
(() => {
    "use strict";

    const main = () => {
        const
            d = new Date(),
            nextMonth = 1 + d.getMonth(),
            nextDay = 1 + d.getDate(),
            dtd = `${nextMonth}/${nextDay}`;

        const nesting = [
            `Practice Sessions → ${dtd}:`,
            [
                [
                    "Session A → 6:30—7:30 → Cards →",
                    [
                        ["Practice 1", []]
                    ]
                ],
                [
                    "Session B → 8:30—9:30 → Coins →",
                    [
                        ["Practice 2", []]
                    ]
                ],
                [
                    "Session C → 10:30—11:30 → Sleight-of-Hand →",
                    [
                        ["Practice 3", []]
                    ]
                ]
            ]
        ];

        return Application("TaskPaper").documents[0]
            .evaluate({
                script: `${TaskPaperContext}`,
                withOptions: {
                    nesting
                }
            });
    };

    // ---------------- TASKPAPER CONTEXT ----------------

    const TaskPaperContext = (editor, options) => {

        const newParentWithChildren = txt =>
            children => {
                const parent = outline.createItem(txt);

                parent.appendChildren(children);

                return parent;
            };

        const foldTree = f => {
            // A general bottom-up fold over a tree
            // connecting each node to the result of a
            // map over its children.
            const go = tree => f(
                tree[0]
            )(
                tree[1].map(go)
            );

            return go;
        };

        const
            outline = editor.outline,
            now = outline.evaluateItemPath(
                "project Now:"
            )[0];

        return (
            now.parent.insertChildrenBefore(
                foldTree(newParentWithChildren)(
                    options.nesting
                ),
                now
            ),
            "OK"
        );
    };

    return main();
})();

(To further generalise and simplify creating/editing template outlines like these, you can, of course, also use a function which translates any indented text outline to that nested list structure)

4 Likes

Thank you @complexpoint !