This is something for which, in due course, Bike.app may no longer need tags (stylesheets revealing toggled attributes might intrude less on the line, and reward the eye less noisily), but for the moment, I find myself marking things off, as I think them through, with either:
- plain
@done
, or a timestamped: -
@done(2022-07-08 08:13)
etc.
Here is an interim script for toggling a @done
tag (with or without timestamp) in one or more selected (and non-empty) Bike rows.
See: Using Scripts - Bike
Expand disclosure triangle to view JS source
(() => {
"use strict";
// `@done` tag toggled in selected and non-empty
// lines of a Bike.app (1.3.1 Preview) outline.
// Optionally with date-time stamp
// (for simple `@done`, edit tagValue to "" below)
// Rob Trew @2022
// Ver 0.03
// main :: IO ()
// eslint-disable-next-line max-lines-per-function
const main = () => {
// ------------------- OPTIONS -------------------
const tagName = "done";
const tagValue = taskPaperDateString(new Date());
// OR tagValue = "";
// ------------------- TOGGLE --------------------
const
bike = Application("Bike"),
doc = bike.documents.at(0);
return doc.exists() ? (() => {
const
selectedRows = doc.rows.where({
selected: true,
_not: [{
name: ""
}]
});
return Boolean(selectedRows.length) ? (() => {
const
tagRegex = new RegExp(
Boolean(tagValue.length) ? (
`@${tagName}\\(.*\\)`
) : `@${tagName}`, "u"
),
isTagged = Boolean(
tagRegex.exec(
selectedRows.at(0).name()
)
),
updated = isTagged ? (
clearTag(tagRegex)
) : addTag(tagRegex)(tagName)(tagValue);
return (
selectedRows().forEach(row => (
row.name = updated(row.name()),
row.textContent.strikethrough = !(
isTagged
)
)),
isTagged ? (
`@${tagName} cleared`
) : `Tagged @${tagName}`
);
})() : "Nothing selected in Bike";
})() : "No documents open in Bike";
};
// ---------------------- TAGS -----------------------
// clearTag :: Regex -> String -> String
const clearTag = tagRegex =>
rowText => {
const match = tagRegex.exec(rowText);
return Boolean(match) ? (() => {
const
matchStart = match.index,
preTag = rowText.slice(
0, matchStart
).trim(),
postTag = rowText.slice(
matchStart + match[0].length
).trim();
return `${preTag} ${postTag}`.trim();
})() : rowText.trim();
};
// addTag :: String -> String -> String -> String
const addTag = tagRegex =>
tagName => tagValue => txt => {
const
affix = Boolean(tagValue.length) ? (
`@${tagName}(${tagValue})`
) : `@${tagName}`;
return `${clearTag(tagRegex)(txt)} ${affix}`;
};
// --------------------- GENERIC ---------------------
// iso8601Local :: Date -> String
const iso8601Local = dte =>
new Date(dte - (6E4 * dte.getTimezoneOffset()))
.toISOString();
// taskPaperDateString :: Date -> String
const taskPaperDateString = dte => {
const [d, t] = iso8601Local(dte).split("T");
return [d, t.slice(0, 5)].join(" ");
};
// MAIN ---
return main();
})();
Keyboard Maestro macro version:
BIKE Outliner – Toggle @done tag in selected rows - Macro Library - Keyboard Maestro