Help needed to convert html form to KM html prompt

I asked ChatGPT to "Write the code for an html page that contains two vertical multi-line edit boxes next to each other, a Cancel button and an OK button. The width of the page should be 1000 px". It did a good job and returned a page that looks like this in Safari:


Now I'd like to use this html code in an html prompt, and I have the following questions

  • How to adjust the html code / macro to display both edit boxes?
  • How to preset both edit boxes with Local_sourceTerms and Local_targetTerms upon calling the form?
  • How to save any edits to Local_sourceTerms and Local_targetTerms upon clicking OK
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Two Vertical Multi-line Textboxes</title>
    <style>
        body {
            width: 1000px;
            margin: 20px auto; /* Center the content */
            font-family: Arial, sans-serif;
        }
        
        .textbox {
            width: 45%; /* Set the width of each textbox */
            height: 150px; /* Set the height of each textbox */
            box-sizing: border-box;
            padding: 8px;
            margin-bottom: 10px;
        }

        .button-container {
            display: flex;
            justify-content: space-between;
        }

        .button-container button {
            padding: 10px;
            cursor: pointer;
        }
    </style>
</head>
<body>
    <textarea class="textbox" placeholder="Textbox 1"></textarea>
    <textarea class="textbox" placeholder="Textbox 2"></textarea>

    <div class="button-container">
        <button onclick="cancelClicked()">Cancel</button>
        <button onclick="okClicked()">OK</button>
    </div>

    <script>
        function cancelClicked() {
            alert('Cancel button clicked!');
        }

        function okClicked() {
            alert('OK button clicked!');
        }
    </script>
</body>
</html>

Screenshot 2023-12-21 at 10.26.16
Test - Add new term pairs via form.kmmacros (2.7 KB)

If you decorate each of those two textareas with a distinct id attribute,
you can obtain a reference to their .value (i.e. to any entered text)
with document.getElementById(idString).value.

e.g.

Expand disclosure triangle to view HTML source
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Two Vertical Multi-line Textboxes</title>
    <style>
        body {
            width: 1000px;
            margin: 20px auto;
            /* Center the content */
            font-family: Arial, sans-serif;
        }

        .textbox {
            width: 45%;
            /* Set the width of each textbox */
            height: 150px;
            /* Set the height of each textbox */
            box-sizing: border-box;
            padding: 8px;
            margin-bottom: 10px;
        }

        .button-container {
            display: flex;
            justify-content: space-between;
        }

        .button-container button {
            padding: 10px;
            cursor: pointer;
        }
    </style>
</head>

<body>
    <textarea id="leftBox" class="textbox" placeholder="Textbox 1"></textarea>
    <textarea id="rightBox" class="textbox" placeholder="Textbox 2"></textarea>

    <div class="button-container">
        <button onclick="cancelClicked()">Cancel</button>
        <button onclick="okClicked()">OK</button>
    </div>

    <script>
        function cancelClicked() {
            alert('Cancel button clicked!');
        }

        function okClicked() {
            const
                [leftText, rightText] = [
                    "leftBox", "rightBox"
                ]
                .map(k => document.getElementById(k).value);

            alert(`${leftText}\n\n${rightText}`);
        }
    </script>
</body>

</html>

Thank you. But my knowledge is so poor that I cannot combine this to a macro. Could you please help?

Clicking Help in the Floating HTML Prompt action's gearwheel takes us to:
action:Custom HTML Prompt [Keyboard Maestro Wiki]

Where we get details for:

  • Setting height and width (e.g. by supplying a value string to a data-kmwindow attribute in the HTML <body> tag
  • Initialising values in the body of a custom KMInit function
  • Reading HTML page values and updating KM variable values in the body of a custom KMWillCloseWindow function.

Others, with more experience of these prompts, can probably show something closer to best practice, but roughly:

Parallel editable text areas (in KM HTML prompt).kmmacros (8.7 KB)


Expand disclosure triangle to view HTML source
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Two Vertical Multi-line Textboxes</title>
    <style>
        body {
            width: 1000px;
            margin: 20px auto;
            /* Center the content */
            font-family: Arial, sans-serif;
        }

        .textbox {
            width: 45%;
            /* Set the width of each textbox */
            height: 150px;
            /* Set the height of each textbox */
            box-sizing: border-box;
            padding: 8px;
            margin-bottom: 10px;
        }

        .button-container {
            display: flex;
            justify-content: space-between;
        }

        .button-container button {
            padding: 10px;
            cursor: pointer;
        }
    </style>
</head>

<body data-kmwindow="SCREEN(Main,Left,20%),SCREEN(Main,Top,20%),1000,500">
    <textarea id="leftBox" class="textbox"></textarea>
    <textarea id="rightBox" class="textbox"></textarea>

    <div class="button-container">
        <button 
            name="Cancel" 
            type="button" 
            onclick="window.KeyboardMaestro.Cancel('Cancel')">Cancel</button>
        <button name="OK" type="button" onclick="window.KeyboardMaestro.Submit('OK')">OK</button>
    </div>

    <script>
        function KMInit() {
            const kmVar = window.KeyboardMaestro.GetVariable;

            document.getElementById("leftBox").value = (
                kmVar("Local_sourceTerms")
            );
            document.getElementById("rightBox").value = (
                kmVar("Local_targetTerms")
            );
        }

        function KMWillCloseWindow() {
            const 
                km = window.KeyboardMaestro,
                boxValue = k =>
                    document.getElementById(k).value;

            km.SetVariable(
                "Local_updatedSourceTerms", 
                boxValue("leftBox")
            );
            km.SetVariable(
                "Local_updatedTargetTerms", 
                boxValue("rightBox")
            );
        }
    </script>
</body>
</html>

Or expressing the (initial) write and (final) read events in terms of .forEach
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Two Vertical Multi-line Textboxes</title>
    <style>
        body {
            width: 1000px;
            margin: 20px auto;
            /* Center the content */
            font-family: Arial, sans-serif;
        }

        .textbox {
            width: 45%;
            /* Set the width of each textbox */
            height: 150px;
            /* Set the height of each textbox */
            box-sizing: border-box;
            padding: 8px;
            margin-bottom: 10px;
        }

        .button-container {
            display: flex;
            justify-content: space-between;
        }

        .button-container button {
            padding: 10px;
            cursor: pointer;
        }
    </style>
</head>

<body data-kmwindow="SCREEN(Main,Left,20%),SCREEN(Main,Top,20%),1000,500">
    <textarea id="leftBox" class="textbox"></textarea>
    <textarea id="rightBox" class="textbox"></textarea>

    <div class="button-container">
        <button name="Cancel" type="button" onclick="window.KeyboardMaestro.Cancel('Cancel')">Cancel</button>
        <button name="OK" type="button" onclick="window.KeyboardMaestro.Submit('OK')">OK</button>
    </div>

    <script>
        function KMInit() {
            [
                ["leftBox", "Local_sourceTerms"],
                ["rightBox", "Local_targetTerms"]
            ]
                .forEach(
                    ([boxName, kmVarName]) =>
                        document.getElementById(boxName)
                            .value = window.KeyboardMaestro
                                .GetVariable(kmVarName)

                )
        }

        function KMWillCloseWindow() {
            [
                ["leftBox", "Local_updatedSourceTerms"],
                ["rightBox", "Local_updatedTargetTerms"]
            ]
                .forEach(
                    ([boxName, kmVarName]) =>
                        window.KeyboardMaestro.SetVariable(
                            kmVarName,
                            document.getElementById(boxName)
                                .value
                        )
                );
        }
    </script>
</body>

</html>
1 Like

Thank you so much for your great help. I can now do beautiful things with this code.

1 Like

"Beautiful things" like this:


Add new term pairs via form.kmmacros (13.5 KB)

One last improvement that I want to make and for which I cannot find the answer on the web: How to horizontally center these two edit boxes, since the form is quite ugly now:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>New term pairs</title>
    <style>
        body {
            width: 800px;
            margin: 20px auto;
            /* Center the content */
            font-family: Arial, sans-serif;
        }

        .textbox {
            width: 45%;
            /* Set the width of each textbox */
            height: 300px;
            /* Set the height of each textbox */
            box-sizing: border-box;
            padding: 8px;
            margin-bottom: 10px;
            font-size: 15px;
        }

        .button-container {
            display: flex;
            justify-content: center;
            width: 90%;
        }

        .button-container button {
            padding: 10px;
            cursor: pointer;
        }
    </style>
</head>

<body data-kmwindow="SCREEN(Main,Left,30%),SCREEN(Main,Top,30%),800,390">
    <textarea id="leftBox" class="textbox"></textarea>
    <textarea id="rightBox" class="textbox"></textarea>

    <div class="button-container">
        <button 
            name="Cancel" 
            type="button" 
            onclick="window.KeyboardMaestro.Cancel('Cancel')">Cancel</button>
        <button name="OK" type="button" onclick="window.KeyboardMaestro.Submit('OK')">OK</button>
    </div>

    <script>
        function KMInit() {
            const kmVar = window.KeyboardMaestro.GetVariable;

            document.getElementById("leftBox").value = (
                kmVar("Local_sourceTerms")
            );
            document.getElementById("rightBox").value = (
                kmVar("Local_targetTerms")
            );
        }

        function KMWillCloseWindow() {
            const 
                km = window.KeyboardMaestro,
                boxValue = k =>
                    document.getElementById(k).value;

            km.SetVariable(
                "Local_updatedSourceTerms", 
                boxValue("leftBox")
            );
            km.SetVariable(
                "Local_updatedTargetTerms", 
                boxValue("rightBox")
            );
        }
    </script>
</body>
</html>
1 Like

And then I thought, why not ask ChatGPT again, about how to horizontally center the two text boxes:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Centered Multi-line Textboxes and Buttons</title>
    <style>
        body {
            width: 1000px;
            margin: 20px auto; /* Center the content horizontally */
            font-family: Arial, sans-serif;
        }
        
        .container {
            text-align: center; /* Center the children horizontally */
        }

        .textbox {
            width: 45%; /* Set the width of each textbox */
            height: 150px; /* Set the height of each textbox */
            box-sizing: border-box;
            padding: 8px;
            margin-bottom: 10px;
        }

        .button-container {
            display: inline-block; /* Maintain inline block to center */
            margin-top: 10px;
        }

        .button-container button {
            padding: 10px;
            cursor: pointer;
        }
    </style>
</head>
<body>
    <div class="container">
        <textarea class="textbox" placeholder="Textbox 1"></textarea>
        <textarea class="textbox" placeholder="Textbox 2"></textarea>

        <div class="button-container">
            <button onclick="cancelClicked()">Cancel</button>
            <button onclick="okClicked()">OK</button>
        </div>
    </div>

    <script>
        function cancelClicked() {
            alert('Cancel button clicked!');
        }

        function okClicked() {
            alert('OK button clicked!');
        }
    </script>
</body>
</html>

Nice!

Demo:
IMG_8364

1 Like