In the meanwhile, I’m personally using a keystroke bound to a scripted strikethrough and @done
(timestamp)
:
BIKE Outliner – Toggle @done tag in selected rows - Macro Library - Keyboard Maestro Discourse
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();
})();
To test in Script Editor, set the language selector at top left to JavaScript
.
See: Using Scripts - Bike