For quick application/clearing of frequently used prototypes, we can set up a Keyboard Maestro shortcut, defined in terms of JavaScript for Automation or AppleScript:
JavaScript for Automation source:
(() => {
'use strict';
// RobTrew (Twitter @ComplexPoint) 2019
// Ver 0.02 (Keyboard Maestro version)
// Name of prototype to toggle on/off for all selected notes.
// Edit to exactly match the name of a prototype in your document:
const
kme = Application('Keyboard Maestro Engine'),
strPrototype = kme.getvariable('prototypeName');
// OR for use outside Keyboard Maestro, comment out the above,
// and set the value of strPrototype here directly, e.g.
// const strPrototype = 'MyCustomPrototype'
// main :: Tbx IO ()
const main = () =>
// Named prototype toggled on or off for
// all the selected notes.
either(
x => 'Not toggled: (' + x + ')',
x => 0 < x.length ? ( // Name string not empty
'Prototype now: ' + x
) : ('Prototype cleared'),
bindLR(
frontDocLR(),
d => bindLR(
allSelectedNotesLR(d),
notes => {
const k = toggledValue(notes)(strPrototype);
return (
prototypesUpdated(notes)(k),
Right(k)
);
}
)
)
);
// TINDERBOX FUNCTIONS --------------------------------
// allSelectedNotesLR :: Tbx Doc -> Either String [Tbx Note]
const allSelectedNotesLR = doc => {
// Either the selected notes, or an
// explanatory message if none are selected.
const selns = doc.selections;
return 0 < selns.length ? (
Right(selns())
) : Left('No note selected in ' + doc.name());
};
// frontDocLR :: Tbx IO () -> Either String Tbx Doc
const frontDocLR = () => {
// Either the front document in Tinderbox, or an
// explanatory message if no documents are open.
const ds = Application('Tinderbox').documents;
return 0 < ds.length ? (
Right(ds.at(0))
) : Left('No documents open in Tinderbox');
};
// prototypesUpdated :: [Tbx Note] -> String -> Tbx IO ()
const prototypesUpdated = notes => k =>
notes.forEach(x => {
showLog('Changed:', x.name(), 'prototype', k);
x.attributes.byName('Prototype').value = k;
});
// toggledValue :: [Tbx Note] -> String -> String
const toggledValue = notes => k =>
notes[0].attributes.byName('Prototype').value() !== k ? k : '';
// GENERIC FUNCTIONS ----------------------------------
// https://github.com/RobTrew/prelude-jxa
// 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);
// concat :: [[a]] -> [a]
// concat :: [String] -> String
const concat = xs =>
0 < xs.length ? (() => {
const unit = 'string' !== typeof xs[0] ? (
[]
) : '';
return unit.concat.apply(unit, xs);
})() : [];
// 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;
// showLog :: a -> IO ()
const showLog = (...args) =>
console.log(
args
.map(JSON.stringify)
.join(' -> ')
);
// MAIN ---
return main();
})();