Using HTML prompt as a message similar to "dialog window" [SOLVED]

I have this code for an HTML prompt and I would like to use it as a normal "dialog" window. When I click "Cancel" it's still running the macro (I want it to abort the macro completely) and if I click "Continue" it keeps running the macro / next actions
(This is a modified version of an HTML prompt kindly provided by @noisneil).
I will eventually delete some of the CSS styles once the action is working, so no need to focus on that for now. I might even use some of them to target something else in the message, so for now I want to keep them there.

<!DOCTYPE html>
<html>
    <head>
        <title>New message</title>
        <style>
            body {
                font-family: system-ui, sans-serif;
                background-color: #1E1E1E;
                color: #ffffff;
            }

            .container {
                display: flex;
                flex-direction: column;
                align-items: center;
            }

            .field {
                display: flex;
                flex-direction: column;
                margin-bottom: 10px;
                border-radius: 5px;
            }

            .field label {
                margin-bottom: 5px;
                color: #f2f2f2;
                font-size: small;
            }

            .field input,
            .field textarea {
                width: 300px;
                padding: 5px;
                color: #f2f2f2;
                border: 0px;
                background-color: #373737;
                border-radius: 5px;
                font-size: 13px;
            }

            .field textarea {
                height: 15em;
                resize: none;
            }

            .buttons button {
                border: none;
                cursor: pointer;
                padding: 6px 16px;
                border-radius: 5px;
                font-size: 12px;
            }

            .buttons button:first-child {
                background-color: #565655;
                color: #fff;
            }

            .buttons button:last-child {
                background-color: #1e77d0;
                color: #fff;
            }
        </style>
    </head>

    <body data-kmwindow="380,355">
        <div class="container">
            <p>This is a sample text</p>
            <div class="buttons">
                <button onclick="cancel()">Cancel</button>
                <button onclick="continueMacro()">
                    Continue (&#8984;&#8629;)
                </button>
            </div>
        </div>
        <script>

            // Listen for the '⌘↵' key combination and trigger the 'continueMacro' function
            document.addEventListener("keydown", function (event) {
                if (event.metaKey && event.keyCode === 13) {
                    continueMacro();
                }
            });

            function continueMacro() {

                // Close the prompt
                window.KeyboardMaestro.Submit("Continue Macro");
            }
            function cancel() {

                // Close the prompt
                window.KeyboardMaestro.Cancel();
            }
        </script>
    </body>
</html>

Make sure to read the docs carefully

So 'cancel' will close the window, yes, but your macro has no idea what the window did. You have to tell KM that the user wants to stop the macro from the HTML prompt itself. There are a few ways to do this.

You can 'submit' a form (with a value that indicates 'cancel')
You can set a KM variable then just close the window

Either way, the bottom line is you have to explicitly communicate from the HTML window back to KM the user's wishes.

1 Like

For a very simple example of this, see my The Decision Maker macro, which acts on keys pressed while the HTML box is onscreen. As an example, here's the Javascript for the Control key:

if (event.ctrlKey) {
    window.close();
    window.KeyboardMaestro.Submit('ControlKey')
}

That submit bit is the data that gets returned to Keyboard Maestro, in the form of the %HTMLResult% token. Later on, I act based on the value returned in that token with a Case statement:

You should be able to do something similar in your macro.

-rob.

1 Like

Thank you for mentioning the %HTMLResult% token :raised_hands:
I was trying to use the IF THEN using the %PromptButton%, for some reason.

Without making any changes to my HTML action, I just did this and it's working now:

image

1 Like

Is there a way to also receive the ESCAPE key as if it was the Cancel button?
Right now if I press ESC it assumes I clicked Continue

I use this in MacroBackerUpper's control box:

if (event.key === "Escape") {
	window.close();
 	window.KeyboardMaestro.Submit('Cancel')
}

Then I check for Cancel in the %HTMLResult% token and cancel the macro.

-rob.

1 Like

I asked ChatGPT and I got this:

if (event.key === "Escape" || event.keyCode === 27) {
                cancel();
            }

Is there any difference between this and your solution?

I'm no Javascript expert, but I think that just handles two different ways that various Javascript interpreters might see keypresses? Key code 27 is the Escape key, so that's just an "or" for the key by name or the key by code.

But I think what you have there would only cancel the prompt, not the entire macro (but that's just a guess, based on Javascript not knowing natively how to cancel a KM macro?).

-rob.

1 Like

But aren't both solutions not canceling the macro per se? They are both sending the result to the next action and then the next action is what determines what happens, right? In this case an IF THEN or the Switch actions

One thing I noticed though is that sometimes I would click the button and it would not do anything so maybe the window.close(); can help here

So I guess I can merge both solution like this:

if (event.key === "Escape" || event.keyCode === 27) {
	window.close();
 	window.KeyboardMaestro.Submit('Cancel')
}

As noted, I'm no expert on Javascript or its KM integration. It's my understanding that if you just say cancel in the Javascript, then that's what happens: The Javascript sends the cancel command to the window, and the macro proceeds. But what I don't know is if that intrinsically returns a Cancel token as well.

When I wrote my version, someone explained the submit method to me (it's on the forums, somewhere), and it made logical sense to me, so that's how I implemented it: I return a value for each keypress, so I can then act on those keypresses in the macro.

-rob.

I was tidying things up a little bit and I got to this final version

 <body data-kmwindow="380,355">
        <div class="container">
            <p>This is a sample text</p>
            <div class="buttons">
                <button onclick="cancel()">Cancel</button>
                <button onclick="continueMacro()">Continue</button>
            </div>
        </div>
        <script>
            document.addEventListener("keydown", function (event) {
                
                // Listen for the ENTER key and output the word "Continue" to KM's %HTMLResult% token
                if (event.key === "Enter" || event.keyCode === 13) {
                    window.close();
                    window.KeyboardMaestro.Submit("Continue");
                }
                
                // Listen for the ESCAPE key and output the word "Cancel" to KM's %HTMLResult% token
                if (event.key === "Escape" || event.keyCode === 27) {
                    window.close();
                    window.KeyboardMaestro.Submit("Cancel");
                }
            });

            function continueMacro() {
                // Close the prompt and output the word "Continue" to KM's %HTMLResult% token
                window.close();
                window.KeyboardMaestro.Submit("Continue");
            }

            function cancel() {
                // Close the prompt and output the word "Cancel" to KM's %HTMLResult% token
                window.close();
                window.KeyboardMaestro.Submit("Cancel");
            }
        </script>
    </body>

It's working and it's a lot cleaner and easier to understand.
Thanks again for your help. I learned the very basics of Javascript a long time ago, but it's one of those things that if you don't use it often, you tend to forget.

1 Like

Sorry, I just noticed another issue.
When I click the red button to close the window:
image

...it assumes I want to Continue instead of Canceling.
Do you know how to change this behavior?

I don't know anything at all about how the red buttons function, beyond closing the window. I don't think Javascript can see those events, though.

You could just disable the window chrome (on the gear menu), so those buttons don't exist :).

-rob.

I don't think I have that option:
image

Where is it?

One "trick" I used for now is to reverse the behavior of the Cancel and Continue buttons. So the Cancel is sending a Continue message and the Continue button is sending a Cancel message. Since the red button is sending a Continue message, they all behave as they should. It doesn't make sense in the code itself, but I have a comment on the macro explaining this until/if I find a solution for this.

Uncheck "Has Title." Note that if you do this, you can only close the window via the macro/Javascript or by restarting the KM engine.

-rob.

1 Like

I tried that and it was still showing the title.
I guess it's that "bug" with KM where you make changes to a macro and the first time you run it it's still loading the previous state. I always tend to run the macros twice, the first one to "unlock" the new version. It's a big annoying that we have to do this, but...

Thanks for that tip. I will definitely do that! :muscle: