A simple macro which just generates a Markdown list of the headers in the web page currently loaded in Safari. (Or, with a minor edit, in Chrome).
Simple Markdown TOC for current Safari page (demo).kmmacros (21.3 KB)
Really intended as an illustration of how you can pass a JS function from Javascript for Applications to Safari or Chrome Browser JS, and get a result back. There's a lot of power in the browser, particularly for parsing, so it can be a useful resource.
A generic JXA function
evalJSinBrowser(fnMain, lstArgs, strBrowser)
Takes:
- a reference to a function defined in Javascript for Applications
- an array of arguments to that function, and
- the name of a browser: "Safari" or "Google Chrome"
and returns the result of the browser evaluation as a string.
// Evaluate a JS function application in a named browser (Chrome | Safari)
// fn --> [arg] --> strBrowserName --> a
function evalJSinBrowser(fnMain, lstArgs, strBrowser) {
// Interface to the browser,
var strDefault = "Safari",
blnSafari = ((
strBrowser = ((strBrowser || '').indexOf(strDefault) === 0) ?
strDefault : "Google Chrome"
) === strDefault),
appBrowser = Application(strBrowser),
// and an open browser window (new if none exists).
lstWins = appBrowser.windows(),
lngWins = lstWins.length,
oWin = lngWins ? lstWins[0] : blnSafari ?
appBrowser.Document().make() && appBrowser.windows[0] :
appBrowser.Window().make(),
// Code of an fnMain().apply(null, lstArgs) function application
strJS = [
'(',
fnMain.toString(),
').apply(null, ',
JSON.stringify(lstArgs), ');'
].join('');
// Result of the function application
return (
blnSafari ?
appBrowser.doJavaScript(
strJS, {
"in": oWin.tabs[0]
}
) :
oWin.activeTab.execute({
"javascript": strJS
})
);
}
For most purposes it's probably easier to use one of KM's built-in Execute JS in Browser
actions, but this approach can be a useful way, within a JXA script, of flexibly delegating something (parsing in particular) to a browser engine.
( It also eases the editing of the browser JS function(s) – you can do this in Script Editor or another text editor as part of the JXA code, and take advantage of linters, code formatters etc.
evalJSinBrowser(fnMain, lstArgs, strBrowser)
takes care of converting the referenced function to a code string in which it is applied to the array of arguments).