If I had a native keyboard shortcut that executed that, I’d be happy!
In the meanwhile, this JXA script assumes installation of a current version of Keyboard Maestro - you can use it on its own (as long as KM and TaskPaper 3 are both installed), but you can also, of course, paste it into a KM Execute a JavaScript for Automation action, and use that to assign a keystroke to it.
(() => {
// Click-Toggle Show Project in Sidebar of TaskPaper 3
// DEPENDENCIES:
// Assumes installation of Keyboard Maestro 8, and TaskPaper 3
// USE: This is a JavaScript for Automation script, which can be
// tested in Script Editor (with the language tab set to JavaScript)
// From Script Menu, or as a Keyboard Maestro
// 'Execute a JavaScript for Automation' action
// Rob Trew (c) 2018
// MIT License
// Ver 0.5 2018-01-11
// 0.5 In case of wider sidebars set clicked horizontal to X + (W-10)
// 0.4 (Finally posted the correct version :-)
// 0.3 (Simplified (>>=) bindMay chain)
// 0.2 Added the Opt to Opt-Click
// main :: JS Function -> FilePath -> a
'use strict';
// GENERIC FUNCTIONS --------------------------------------
// Just :: a -> Just a
const Just = x => ({
type: 'Maybe',
Nothing: false,
Just: x
});
// Nothing :: () -> Nothing
const Nothing = (optionalMsg) => ({
type: 'Maybe',
Nothing: true,
msg: optionalMsg
});
// append (++) :: [a] -> [a] -> [a]
const append = (xs, ys) => xs.concat(ys);
// bindMay (>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
const bindMay = (mb, mf) =>
mb.Nothing ? mb : mf(mb.Just);
// isMaybe :: a -> Bool
const isMaybe = x =>
x.type === 'Maybe';
// map :: (a -> b) -> [a] -> [b]
const map = (f, xs) => xs.map(f);
// readFile :: FilePath -> IO String
const readFile = strPath => {
var error = $(),
str = ObjC.unwrap(
$.NSString.stringWithContentsOfFileEncodingError(
$(strPath)
.stringByStandardizingPath,
$.NSUTF8StringEncoding,
error
)
);
return Boolean(error.code) ? (
ObjC.unwrap(error.localizedDescription)
) : str;
};
// takeBaseName :: FilePath -> String
const takeBaseName = strPath =>
strPath !== '' ? (
strPath[strPath.length - 1] !== '/' ? (
strPath.split('/')
.slice(-1)[0].split('.')[0]
) : ''
) : '';
// takeExtension :: FilePath -> String
const takeExtension = strPath => {
const
xs = strPath.split('.'),
lng = xs.length;
return lng > 1 ? (
'.' + xs[lng - 1]
) : '';
};
// File name template -> temporary path
// (Random digit sequence inserted between template base and extension)
// tempFilePath :: String -> IO FilePath
const tempFilePath = template =>
ObjC.unwrap($.NSTemporaryDirectory()) +
takeBaseName(template) + Math.random()
.toString()
.substring(3) + takeExtension(template);
// MAIN ---------------------------------------------------
// jsoDoScript :: Object (Dict | Array) -> IO ()
const jsoDoScript = jso => {
const strPath = tempFilePath('tmp.plist');
return (
Application('Keyboard Maestro Engine')
.doScript((
$(Array.isArray(jso) ? jso : [jso])
.writeToFileAtomically(
$(strPath)
.stringByStandardizingPath,
true
),
readFile(strPath)
)),
true
);
};
const
se = Application('System Events'),
procs = se.applicationProcesses.where({
name: 'TaskPaper'
}),
mbResult =
bindMay(
bindMay(
bindMay(
procs.length > 0 ? (
Just(procs.at(0))
) : Nothing('TaskPaper not running.'),
proc => {
const ws = proc.windows;
return ws.length > 0 ? (
Just(ws.at(0)
.splitterGroups.at(0)
.scrollAreas)
) : Nothing('No TaskPaper windows open.')
}
),
areas => areas.length > 1 ? (
Just(areas.at(0)
.outlines.at(0)
.rows.at(1)
.uiElements.at(0))
) : Nothing('Sidebar not open.')
),
cell => {
const [
x, y, w, h
] = append(cell.position(), cell.size());
const [
sx, sy
] = map(
n => n.toString(), [x + (w - 10), y + (h / 2)]
);
return (
// Effect
jsoDoScript([{
"ReopenWindows": false,
"AllWindows": true,
"MacroActionType": "ActivateApplication",
"AlreadyActivatedActionType": "Normal",
"TimeOutAbortsMacro": true,
"Application": {
"NewFile": "/Applications/TaskPaper.app",
"BundleIdentifier": "com.hogbaysoftware.TaskPaper3.direct",
"Name": "TaskPaper"
}
}, {
"MacroActionType": "PauseUntil",
"TimeOutAbortsMacro": true,
"Conditions": {
"ConditionList": [{
"ApplicationConditionType": "Active",
"ConditionType": "Application",
"Application": {
"NewFile": "/Applications/TaskPaper.app",
"BundleIdentifier": "com.hogbaysoftware.TaskPaper3.direct",
"Name": "TaskPaper"
}
}],
"ConditionListMatch": "Any"
}
},
{
"UseFormat": false,
"MacroActionType": "SetVariableToCalculation",
"Variable": "instanceMouseX",
"Text": "MOUSEX()"
},
{
"UseFormat": false,
"MacroActionType": "SetVariableToCalculation",
"Variable": "instanceMouseY",
"Text": "MOUSEY()"
},
{
"ClickCount": 0,
"DragVerticalPosition": "0",
"MacroActionType": "MouseMoveAndClick",
"Modifiers": 0,
"Button": 0,
"Fuzz": 15,
"Action": "Move",
"DisplayMatches": false,
"DragHorizontalPosition": "0",
"RestoreMouseLocation": false,
"VerticalPositionExpression": sy,
"RelativeCorner": "TopLeft",
"HorizontalPositionExpression": sx,
"Relative": "Absolute",
"MouseDrag": "None"
},
{
"Time": ".1",
"MacroActionType": "Pause",
"TimeOutAbortsMacro": true
},
{
"ClickCount": 1,
"DragVerticalPosition": "0",
"MacroActionType": "MouseMoveAndClick",
"Modifiers": 2048,
"Button": 0,
"Fuzz": 15,
"Action": "MoveAndClick",
"DisplayMatches": false,
"DragHorizontalPosition": "0",
"RestoreMouseLocation": false,
"VerticalPositionExpression": sy,
"RelativeCorner": "TopLeft",
"HorizontalPositionExpression": sx,
"Relative": "Absolute",
"MouseDrag": "None"
},
{
"ClickCount": 0,
"DragVerticalPosition": "0",
"MacroActionType": "MouseMoveAndClick",
"Modifiers": 0,
"Button": 0,
"Fuzz": 15,
"Action": "Move",
"DisplayMatches": false,
"DragHorizontalPosition": "0",
"RestoreMouseLocation": false,
"VerticalPositionExpression": "instanceMouseY",
"RelativeCorner": "TopLeft",
"HorizontalPositionExpression": "instanceMouseX",
"Relative": "Absolute",
"MouseDrag": "None"
}
]),
Just([sx, sy])
)
}
);
return mbResult.Nothing ? (
mbResult.msg
) : ('Clicked TaskPaper sidebar at: ' + mbResult.Just);
})();
(Updated to 0.2 above – added the ⌥ as in Opt-Click )
Hi Rob,
Doesn’t work for me. I am guessing this is because I have made my sidebar wider.
Which number should I change to make the click work on my wider sidebar?
Is there an easy way to measure what the number should be?
Example:
Not your fault – I posted a version with dependencies - correcting to 0.4 now
And in 0.5 I’ve changed the clicked X to (X + (W-10)
) which should be insensitive to sidebar width, I think,
Thanks! Version 0.5 works on my wide sidebar!
Posted in a Keyboard Maestro macro (which additionally opens the sidebar if it finds it closed) at:
(Incidentally, there may be a redundant pause action in there:
{
"Time": "0.1",
"MacroActionType": "Pause",
"TimeOutAbortsMacro": true
}
I find that in practice I can I either remove it or set the Time string to “0” on my system.
{
"Time": "0",
"MacroActionType": "Pause",
"TimeOutAbortsMacro": true
}
Removed it and it works fine on my MacBook Pro (15-inch, 2016).
@Jim @complexpoint In latest preview release I’ve added “View > Show Sidebar And Expand Completely”:
@jessegrosjean — works well here! The only thing I would add is a native keyboard shortcut.
Interesting discussion! Thanks for all the juicy details.