A macro for Jesse Grosjean's Bike Outliner.
Toggles the task-completed status of all selected (non-empty) rows.
The task
row type – displaying a completion check-box – is assigned to any selected (non-empty) rows which are not yet of that type.
BIKE – Toggle Task Completion in selected row(s).kmmacros (26 KB)
Expand disclosure triangle to view JS source
(() => {
"use strict";
// Toggle task-completed for one or more selected Bike rows.
// Affects non-empty rows only.
// Affected rows are set to type "task" where necessary.
// All selected rows are taken to the same status.
// Where their starting status is mixed, the new status
// is the opposite of that of the first selected task.
// Rob Trew @2023
// Ver 2.3
// ---------------------- MAIN -----------------------
// main :: IO ()
const main = () => {
const
bike = Application("Bike"),
doc = bike.documents.at(0);
return doc.exists()
? toggleCompleted(bike)(
doc.rows.where({
selected: true,
_not: [{name: ""}]
})()
)
: "No document open in Bike.";
};
// ---------------------- BIKE -----------------------
// bikeAttribFoundOrCreated :: Bike Application ->
// String -> Bike Row -> Bike Attribute
const bikeAttribFoundOrCreated = bikeApp =>
// A reference to an attribute (of the given name)
// for a particular row.
name => row => {
const maybeAttrib = row.attributes.byName(name);
return maybeAttrib.exists()
? maybeAttrib
: (() => {
const
attrib = new bikeApp.Attribute({
name
});
return (
row.attributes.push(attrib),
attrib
);
})();
};
// taskCleared :: Bike Application ->
// Bike Row -> IO Bike Row
const taskCleared = bike =>
// A row with any `data-done` attribute removed.
row => {
const mb = row.attributes.byName("data-done");
return (
mb.exists() && bike.delete(mb),
row
);
};
// taskCompleted :: Bike Application ->
// Bike Row -> IO Bike Row
const taskCompleted = bike =>
// A row with an ISO8601 time stamp value for
// the `data-done` attribute.
// If the attribute is newly created the
// time-stamp is taken from current system time.
row => {
const
attrib = bikeAttribFoundOrCreated(bike)(
"data-done"
)(row);
return (
attrib.value = attrib.value() || (
new Date()
)
.toISOString(),
row
);
};
// taskTypeChecked :: Bike Row -> IO Bike Row
const taskTypeChecked = row =>
// A task with its type set to "task".
(
("task" !== row.type()) && (row.type = "task"),
row
);
// toggleCompleted :: Application ->
// [Bike Row] -> IO String
const toggleCompleted = bikeApp =>
// A message reporting on the number and new
// (toggled) task-completion status of the
// given list of Bike rows.
rows => {
const n = rows.length;
return 0 < n
? (() => {
const
iTask = rows.findIndex(
x => "task" === x.type()
),
newStatus = !(
-1 !== iTask
? rows[iTask].attributes
.byName("data-done")
.exists()
: false
),
statusName = newStatus
? "completed"
: "reset to incomplete";
const f = newStatus
? x => taskCompleted(bikeApp)(
taskTypeChecked(x)
)
: x => taskCleared(bikeApp)(
taskTypeChecked(x)
);
return (
rows.forEach(f),
`${n} tasks ${statusName}.`
);
})()
: "No rows selected in Bike.";
};
// MAIN ---
return main();
})();