Is there a way to display the number of children tasks a parent task/project has when it is collapsed?
thanks
Is there a way to display the number of children tasks a parent task/project has when it is collapsed?
thanks
This is what I came up with:
function TaskPaperContextScript(editor, options) {
var selection = editor.selection.selectedItems.filter(function(x) {
return x.getAttribute('data-type') === 'project';
});
for(var i in selection) {
editor.outline.groupUndoAndChanges(function() {
var item = selection[i];
var idx = item.bodyString.search(/ \[.+\/.+\]:/);
if (idx > -1) {
item.bodyString = item.bodyString.substring(0, idx) + ':';
}
else {
if (item.hasChildren) {
var done = item.children.filter(function(x) {
return x.hasAttribute('data-done');
});
item.bodyString = item.bodyString.substring(0, item.bodyString.length-1) + " [" + done.length + "/" + item.children.length + "]:";
//item.appendBody(" [" + done.length + "/" + item.children.length + "]");
}
}
});
}
}
Application("TaskPaper").documents[0].evaluate({
script: TaskPaperContextScript.toString()
});
There is a side effect of this code which is quite annoying though: cursor is moved to the next line.
Not really. With a script (as you’ve nicely done) you can insert the answer into your document content. But that’s a big problematic as a general solution, because you likely don’t really want that data saved in your document. Longer term TaskPaper might get the ability to display decorations in the next big release (4) (similar to what FoldingText does) attached to items in your outline. With that in place you could make a pretty nice script to do what you want, but until then the route you’ve taken is best.
Any ideas why the cursor moves to the next line with the code above? (by now this is driving me nuts already )
… and the solution is:
editor.moveSelectionToItems(startSelection);
sorry old topic, where did you put this line of code?
I guess another approach might be to generate a summary report of (tasks completed / total number of tasks) in each project and subproject, perhaps:
A sketch:
(() => {
'use strict';
// TaskPaper 3 script
// Copy to clipboard (and display in dialog)
// an indented breakdown of the
// (number of tasks completed / total tasks)
// in each project and subproject.
// Rob Trew 2019
// Ver 0.02
// JS FOR AUTOMATION EVALUATION CONTEXT ---------------
const main = () => {
const ds = Application('TaskPaper').documents;
return either(alert('Problem'))(
dct => {
const
strHeadLine = str(dct.done) + ' tasks of ' +
dct.total + ' completed',
strOutline = unlines(dct.breakdown);
return (
Object.assign(
Application.currentApplication(), {
includeStandardAdditions: true
}
).setTheClipboardTo(strHeadLine + '\n\n' + strOutline),
alert(strHeadLine)(strOutline)
);
}
)(bindLR(
ds.length > 0 ? (
Right(ds.at(0))
) : Left('No TaskPaper documents open')
)(d => Right(d.evaluate({
script: tp3Context.toString()
}))));
};
// TASKPAPER JS EVALUATION CONTEXT --------------------
const tp3Context = (editor, options) => {
const main = () =>
foldTree(
x => xs => 0 < xs.length ? (() => {
const [intDone, intTotal] = updatedTuple(
add(plusDone(x))
)(
add(succTotal(x))
)(
xs.reduce(
(tupleDoneTotal, p) =>
updatedTuple(add(p.done))(add(p.total))(
tupleDoneTotal
),
[0, 0]
)
);
return {
breakdown: (
isProject(x) ? [
title(x) + ' (' +
str(intDone) + '/' +
str(intTotal) + ')'
] : []
).concat(xs.flatMap(
p => p.breakdown.map(v => ' ' + v)
)),
done: intDone,
total: intTotal
}
})() : {
breakdown: isProject(x) ? (
[title(x)]
) : [],
done: plusDone(x),
total: succTotal(x)
})(
pureTreeTP3(
editor.outline.root
)
);
// TASKPAPER --------------------------------------
// plusDone :: Item -> Int
const plusDone = x =>
(isTask(x) && isDone(x)) ? (
1
) : 0;
// succTotal :: Item -> Int
const succTotal = x =>
isTask(x) ? (
1
) : 0
// isProject :: Item -> Bool
const isProject = x =>
'project' === x.getAttribute('data-type');
// isTask :: Item -> Bool
const isTask = x =>
'task' === x.getAttribute('data-type');
// isDone :: Item -> Bool
const isDone = x =>
x.hasAttribute('data-done');
// str :: a -> String
const str = x => x.toString();
// title :: Item -> String
const title = x => x.bodyContentString + ':';
// GENERIC FUNCTIONS FOR TASKPAPER CONTEXT --------
// Node :: a -> [Tree a] -> Tree a
const Node = v => xs => ({
type: 'Node',
root: v, // any type of value (consistent across tree)
nest: xs || []
});
// add :: Int -> Int -> Int
const add = a => b => a + b;
// foldTree :: (a -> [b] -> b) -> Tree a -> b
const foldTree = f => tree => {
const go = node => f(node.root)(
node.nest.map(go)
);
return go(tree);
};
// pureTreeTP3 :: TP3Item -> Tree TP3Item
const pureTreeTP3 = item => {
const go = x =>
Node(x)(x.hasChildren ? x.children.map(go) : []);
return go(item);
};
// updatedTuple (***) :: (a -> b) -> (c -> d) -> ((a, c) -> (b, d))
const updatedTuple = f => g => tpl => [f(tpl[0]), g(tpl[1])];
// TASKPAPER CONTEXT MAIN
return main();
};
// JXA FUNCTIONS --------------------------------------
// alert :: String => String -> IO String
const alert = title => s => {
const
sa = Object.assign(Application('System Events'), {
includeStandardAdditions: true
});
return (
sa.activate(),
sa.displayDialog(s, {
withTitle: title,
buttons: ['OK'],
defaultButton: 'OK',
withIcon: sa.pathToResource('TaskPaper.icns', {
inBundle: 'Applications/TaskPaper.app'
})
}),
s
);
};
// GENERIC FUNCTIONS ------------------------------
// Left :: a -> Either a b
const Left = x => ({
type: 'Either',
Left: x
});
// Right :: b -> Either a b
const Right = x => ({
type: 'Either',
Right: x
});
// bindLR (>>=) :: Either a -> (a -> Either b) -> Either b
const bindLR = m => mf =>
undefined !== m.Left ? (
m
) : mf(m.Right);
// either :: (a -> c) -> (b -> c) -> Either a b -> c
const either = fl => fr => e =>
'Either' === e.type ? (
undefined !== e.Left ? (
fl(e.Left)
) : fr(e.Right)
) : undefined;
// str :: a -> String
const str = x => x.toString();
// unlines :: [String] -> String
const unlines = xs => xs.join('\n');
// JXA CONTEXT MAIN
return main();
})()