In the meanwhile, one option to experiment with might be a Keyboard Maestro macro:
Pick color for selected Tinderbox 8 notes.kmmacros.zip (11.0 KB)
Which I find I can also run (tho fractionally more slowly) as a stamp from the Tinderbox 8 QuickStamp inspector.
( Paste all of the source below into a new stamp, right down to
})();
JXA_END")
and give the stamp some name like Color Picker
).
runCommand version for Tinderbox 8 stamp, as above
runCommand("osascript -l JavaScript <<JXA_END 2>/dev/null
(() => {
'use strict';
// Pick color for selected notes in Tinderbox 8
// Rob Trew 2020
// Ver 0.01
const main = () => {
const docs = Application('Tinderbox 8').documents;
return either(
alert('Color of selected note(s)')
)(
x => x
)(
bindLR(
0 < docs.length ? (
Right(docs.at(0))
) : Left('No documents open in Tinderbox 8.')
)(
doc => bindLR(
0 < doc.selections.length ? (
Right(doc.selections())
) : Left('Nothing selected in ' + doc.name())
)(notes => {
try {
const
hexColor = '#' + Object.assign(
Application.currentApplication(), {
includeStandardAdditions: true
})
.chooseColor({
defaultColor: chunksOf(2)(
notes[0].color().slice(1)
)
.map(s => parseInt(s, 16) / 255)
})
.map(
x => Math.round(255 * x)
.toString(16).padStart(2, '0')
).join('');
return (
notes.forEach(
x => x.attributes.byName('Color')
.value = hexColor
),
Right(hexColor)
);
} catch (e) {
return Left(e.message)
}
})
)
);
};
// ------------------------JXA-------------------------
// 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'
}),
s
);
};
// -----------------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);
// chunksOf :: Int -> [a] -> [[a]]
const chunksOf = n =>
xs => enumFromThenTo(0)(n)(
xs.length - 1
).reduce(
(a, i) => a.concat([xs.slice(i, (n + i))]),
[]
);
// 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;
// enumFromThenTo :: Int -> Int -> Int -> [Int]
const enumFromThenTo = x1 =>
x2 => y => {
const d = x2 - x1;
return Array.from({
length: Math.floor(y - x2) / d + 2
}, (_, i) => x1 + (d * i));
};
// MAIN ---
return main();
})();
JXA_END")
You can also launch the slightly different version below from any context in which JavaScript for Automation scripts will run. For example macOS Script Editor, with the top left pull-down set to JavaScript
rather than AppleScript
:
JS for Script Editor etc
(() => {
'use strict';
// Pick color for selected notes in Tinderbox 8
// Rob Trew 2020
// Ver 0.01
const main = () => {
const docs = Application('Tinderbox 8').documents;
return either(
alert('Color of selected note(s)')
)(
x => x
)(
bindLR(
0 < docs.length ? (
Right(docs.at(0))
) : Left('No documents open in Tinderbox 8.')
)(
doc => bindLR(
0 < doc.selections.length ? (
Right(doc.selections())
) : Left('Nothing selected in ' + doc.name())
)(notes => {
try {
const
hexColor = '#' + Object.assign(
Application.currentApplication(), {
includeStandardAdditions: true
})
.chooseColor({
defaultColor: chunksOf(2)(
notes[0].color().slice(1)
)
.map(s => parseInt(s, 16) / 255)
})
.map(
x => Math.round(255 * x)
.toString(16).padStart(2, '0')
).join('');
return (
notes.forEach(
x => x.attributes.byName('Color')
.value = hexColor
),
Right(hexColor)
);
} catch (e) {
return Left(e.message)
}
})
)
);
};
// ------------------------JXA-------------------------
// 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'
}),
s
);
};
// -----------------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);
// chunksOf :: Int -> [a] -> [[a]]
const chunksOf = n =>
xs => enumFromThenTo(0)(n)(
xs.length - 1
).reduce(
(a, i) => a.concat([xs.slice(i, (n + i))]),
[]
);
// 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;
// enumFromThenTo :: Int -> Int -> Int -> [Int]
const enumFromThenTo = x1 =>
x2 => y => {
const d = x2 - x1;
return Array.from({
length: Math.floor(y - x2) / d + 2
}, (_, i) => x1 + (d * i));
};
// MAIN ---
return main();
})();