Append to Keyboard Maestro Variable with In-Browser JavaScript?

I am trying to append new id.
I have old IDs variable and want to add new ids.

(function() {  // Update IDs
	var storedIDs = document.kmvar.eb_done_items;
        console.log(storedIDs); // ex.12345, 10993, 44321
        console.log(typeof storedIDs);  //string

	var newID=", " + document.getElementById('descItemNumber').textContent;
        console.log(newID);
	//storedIDs.append(newID);  // Uncaught TypeError: storedIDs.append is not a function
	//document.kmvar.eb_done_items.append('aaaa');
        //storedIDs.push(newID);  // Uncaught TypeError: storedIDs.push is not a function
        console.log(storedIDs);
        
	return newID;
})(); 

It works fine with append KM action. But I want to add it via javascript.
But not working. Am I missing something?

Thank you, :slight_smile:

Hey Sasi,

See: actions:Execute a JavaScript in Browser [Keyboard Maestro Wiki]

See the subheading:

Saving Results to Keyboard Maestro Variables

-Chris

Thank you. :slight_smile:
However, can I save ( append ) in javascript?
Because it gets 1 result ( true or false ) and I need 1 more result ( the new id ).

Just like what I wrote the script. Can I save like the script?

Thank you,


Using Keyboard Maestro Variables

JavaScript in browsers can only GET Keyboard Maestro variables. They cannot be set. If your Keyboard Maestro Variable contains spaces, they must be replaced with underscores in the JavaScript, for example:


The wiki explains what you have to do to save to a Keyboard Maestro variable, i.e., Keyboard Maestro variables cannot be saved to using in-browser JavaScript.

That's not overly surprising, because a web browser is a closed system and is not supposed to be able to affect the operating system directly.

-Chris

2 Likes

@peternlewis – would you please briefly explain how Keyboard Maestro variables work with in-browser JavaScript?

Or – point to one such if you've previously done so.

TIA.

-Chris

Please also see this thread:

Get & Set ( Update ) KM Variable in JS - #2 by ComplexPoint

1 Like

What is not covered in the wiki Execute a JavaScript in Front Browser action?

Using Keyboard Maestro Variables

JavaScript in browsers can only GET Keyboard Maestro variables. They cannot be set. If your Keyboard Maestro Variable contains spaces, they must be replaced with underscores in the JavaScript, for example:

// Get Keyboard Maestro variable "My KM Data"
var myData = document.kmvar.My_KM_Data

:warning: Note that because your variables are passed to the web page, any other scripts running on that web page will have access them, and this could be a privacy issue if the information is misused by the web page.

2 Likes

A KM variable is always a string, so in this first line in your code:

storedIDs = document.kmvar.eb_done_items;

storedIDs is a string – not a Document Object Model element with an append method.

Your eb_done_items appears to be a comma-delimited string.

The steps would be:

  1. Just use the Browser JS action to get and return the value of document.getElementById('descItemNumber').textContent
  2. In a separate KM action, append that value (after a delimiter like ", ") to the existing value of eb done items

In other words, there is no need at all to even read eb done items inside your Browser JS action. All you need to do in there is fetch and return the new id.

You will have to adjust the details, and test, but roughly speaking, this kind of pattern:

1. Fetch ID from browser 2. Append to existing CSV.kmmacros (2.5 KB)

1 Like

Hey Peter,

I was hoping you'd mention how Keyboard Maestro variables were passed into a web page context, and why they can't be affected from same.

This question will come up again, and I'd like to briefly cover it in the wiki.

-Chris

Without wanting to pre-empt Peter:

The second part is easy – browser JS is specifically designed, for security reasons, not to be able to change the state of the system outside the browser, other than by returning a value.

For the first part, if Peter hadn't done this for us, and you yourself wanted to make a JS object called kmvar (the keys and values of which are the full set of KM variable names and values) making it available to arbitrary user JS scripts in Safari, then you could sketch something like the code below, which uses the osascript Safari.[Tab | Window].doJavaScript method, and tests a silly bit of user code which just:

  • adds 2 + 2
  • checks the full contents of kmvar
  • and also lists all the keys in Safari's global evaluation space:

Expand disclosure triangle to view JS Source
(() => {
    "use strict";

    // A simple JS script to evaluate in Safari JS:

    const userJSScript = "[2 + 2, Object.keys(kmvar), Object.keys(this)]";

    // and some basic mechanics for doing that without
    // the help of the `Execute JS in Safari` action,
    // and creating our own access to a `kmvar` object.

    // main :: IO ()
    const main = () => {
        const
            kmvars = Application("Keyboard Maestro Engine").variables,
            safari = Application("Safari"),
            currentTab = safari.windows.at(0).currentTab;

        // KM variable names and values collected into
        // a single JS object.
        const kmvar = Object.fromEntries(
            zip(kmvars.name())(kmvars.value())
        );

        return safari.doJavaScript(
            ["(() => {",
                "'use strict';",
                `const kmvar = ${JSON.stringify(kmvar)};`,
                `return ${userJSScript}`,
                "})();"
            ].join("\n"), {
                in: currentTab
            });
    };

    // --------------------- GENERIC ---------------------

    // zip :: [a] -> [b] -> [(a, b)]
    const zip = xs =>
        // The paired members of xs and ys, up to
        // the length of the shorter of the two lists.
        ys => Array.from({
            length: Math.min(xs.length, ys.length)
        }, (_, i) => [xs[i], ys[i]]);

    return JSON.stringify(main(), null, 2);
})();
1 Like

In short – here at least – passing in a JSON copy of kme.variables as a header to the user's script,
with the the name kmvar bound to the evaluated object.

As @ComplexPoint notes, javaScript is entirely sandboxed to within the page so it cannot access anything outside the page and the script.

Keyboard Maestro provides the Keyboard Maestro variables within the script you run, essentially adding them to the start of your script. They go in to the script, but nothing comes out - the only thing that comes out of the script is the script result, which you can then use to set Keyboard Maestro variables by processing the result of the script.

1 Like

Hokey but...

Could the javascript do an alert() and KM grab that bit of the screen?

Test and see.  :sunglasses:

2 Likes