A hello world document – testing omniJS code from JXA + text editor

One way to run omniJS code on iOS or macOS is with a URL containing url-encoded JavaScript.

https://omni-automation.com provides a useful service for composing encoding and running shorter snippets at https://omni-automation.com/console-graffle.html

Another way is to paste unencoded JavaScript into the omniJS console (OmniGraffle > Scripts > Show Console);

Running omniJS code from a text editor, url-encoded and launched by JXA

For editing and testing slightly longer scripts on macOS, I find it useful to develop and test omniJS scripts from a text editor, using its cousin JXA to url-encode and run the omniJS code from inside the editor.

(Script Editor works fine for this, but I personally prefer Atom and the Atom-script script-running package).

Here, FWIW, is a “Hello world” JXA script, for running in Script Editor etc, which displays a hello world message in a new shape on a new canvas in the active (OmniGraffle 7.3 Test) document, by creating and using an omniJS URL.

(It allows you to type, edit and test the OmniJS code in a text editor, without any quoting or escaping). The top level omniJS function is called main here, and its argument is dctOptions, a JS dictionary through which you can pass in any optional or data values from JXA.

Once the code is written and tested, the URL-encoded version will run on macOS and on iOS OmniGraffle too.

(function () {
    'use strict';
    // Code for omniJS Context ------------------------------------------------

    var dctOptions = {
        msg: "Hello to the omniJS world from JXA !!!"
    };

    // main :: Dictionary -> Console IO ()
    function main(dctOptions) {
        // New canvas created and selected in active OmniGraffle document
        var cnv = addCanvas();
        cnv.layoutInfo.automaticLayout = false;
        ['Right', 'Down'].forEach(function (x) {
            cnv['autosizes' + x] = true;
        });
        document.windows[0].selection.view.canvas = cnv;

        // New shape added to new canvas, using text from dctOptions,
        // passed in by JXA
        var shp = cnv.newShape();
        shp.cornerRadius = 9;
        shp.text = dctOptions.msg;
        shp.textSize = 12;
        shp.geometry = new Rect(100.00, 100.00, 100.00, 100.00);

        // Also send the message text to the OmniJS console at
        // OmniGraffle > Scripts > Show Console
        console.log(dctOptions.msg);
    };


    // Code for JXA Context----------------------------------------------------

    // Using JXA to url-encode and then run the OmniJS code:

    // show :: a -> String
    function show(x) {
        return JSON.stringify(x, null, 2);
    };

    var a = Application.currentApplication(),
        sa = (a.includeStandardAdditions = true, a),

        // Javascript can convert a function to a source code string ...
        strCode = '(' + main.toString() + ')(' + show(dctOptions) + ')',
        strPrefix = 'omnigraffle:///omnijs-run?script=',

        // URL-encode the omniJS source code
        strOmniJSURL = strPrefix + encodeURIComponent(strCode);

    // Make sure that there is an active document in OmniGraffle 7.3 test
    var og = Application('OmniGraffle'),
        ds = og.documents,
        d = ds.length > 0 ? ds.at(0) : ds.push(og.Document());

    // Run the omniJS url
    og.activate();
    sa.openLocation(strOmniJSURL);

    // Copy and return the plain text of the OmniJS code for visual checking
    sa.setTheClipboardTo(strCode);
    return strCode;
})();
2 Likes

As a footnote, if you also want your test-run to open the OmniGraffle 7.3 Test script console, to see anything that has been written to it, you could use an extended version, including a generic menuItemClick() function:

(function () {
    'use strict';
    // Code for omniJS Context ------------------------------------------------

    var dctOptions = {
        msg: "Hello to the omniJS world from JXA !!!"
    };

    // main :: Dictionary -> Console IO ()
    function main(dctOptions) {
        // New canvas created and selected in active OmniGraffle document
        var cnv = addCanvas();
        cnv.layoutInfo.automaticLayout = false;
        ['Right', 'Down'].forEach(function (x) {
            cnv['autosizes' + x] = true;
        });
        document.windows[0].selection.view.canvas = cnv;

        // New shape added to new canvas, using text from dctOptions,
        // passed in by JXA
        var shp = cnv.newShape();
        shp.cornerRadius = 9;
        shp.text = dctOptions.msg;
        shp.textSize = 12;
        shp.geometry = new Rect(100.00, 100.00, 100.00, 100.00);

        // Also send the message text to the OmniJS console at
        // OmniGraffle > Scripts > Show Console
        console.log(dctOptions.msg);
    };


    // Code for JXA Context----------------------------------------------------

    // Using JXA to url-encode and then run the OmniJS code:

    // GENERIC FUNCTIONS
    // show :: a -> String
    function show(x) {
        return JSON.stringify(x, null, 2);
    };

    // menuItemClick :: String -> [String] -> IO Bool
    function menuItemClick(strAppName, lstMenuPath) {
        var intMenuPath = lstMenuPath.length;

        if (intMenuPath > 1) {
            var appProcs = Application('System Events')
                .processes.where({
                    name: strAppName
                }),
                procApp = appProcs.length ? appProcs[0] : undefined;

            if (procApp) {
                Application(strAppName)
                    .activate();

                lstMenuPath.slice(1, -1)
                    .reduce(function (a, x) {
                        return a.menuItems[x].menus[x];
                    }, procApp.menuBars[0].menus.byName(lstMenuPath[0]))
                    .menuItems[lstMenuPath[intMenuPath - 1]].click();
            }
        }
    };

    // JXA MAIN ---------------------------------------------------------------

    var a = Application.currentApplication(),
        sa = (a.includeStandardAdditions = true, a),

        // Javascript can convert a function to a source code string ...
        strCode = '(' + main.toString() + ')(' + show(dctOptions) + ')',
        strPrefix = 'omnigraffle:///omnijs-run?script=',

        // URL-encode the omniJS source code
        strOmniJSURL = strPrefix + encodeURIComponent(strCode);

    // Make sure that there is an active document in OmniGraffle 7.3 test
    var og = Application('OmniGraffle'),
        ds = og.documents,
        d = ds.length > 0 ? ds.at(0) : ds.push(og.Document());

    // Run the omniJS url
    og.activate();
    sa.openLocation(strOmniJSURL);

    // Open the OG Script Console
    menuItemClick('OmniGraffle', ['Scripts', 'Show Console']);

    // Copy and return the plain text of the OmniJS code for visual checking
    sa.setTheClipboardTo(strCode);
    return strCode;
})();
1 Like

Editing rights have expired for the version above, but I notice that the OG7 main menu has changed since it was first written, so

    // Open the OG Script Console
    menuItemClick('OmniGraffle', ['Scripts', 'Show Console']);

Needs to be edited to:

    // Open the OG Script Console
    menuItemClick('OmniGraffle', ['Automation', 'Show Console']);

Let me share a simplified version that only calls the OmniGraflle app and does not create a new canvas.

#!/usr/bin/env osascript -l JavaScript

(function () {
    'use strict';
    // Code for omniJS Context ------------------------------------------------

    var dctOptions = {
        msg: "Hello to the omniJS world from JXA !!!"
    };

    // main :: Dictionary -> Console IO ()
    function main(dctOptions) {

        // Floating point values in this script may be rounded, resulting in minor visual differences from the original


        // Existing canvas in the active OmniGraffle document
        var cnv = document.windows[0].selection.canvas;

        // New shape added to new canvas, using text from dctOptions,
        // passed in by JXA
        var shp = cnv.newShape();
        shp.cornerRadius = 9;
        shp.text = dctOptions.msg;
        shp.textSize = 12;
        shp.geometry = new Rect(100.00, 100.00, 100.00, 100.00);

        // Also send the message text to the OmniJS console at
        // OmniGraffle > Scripts > Show Console
        console.log(dctOptions.msg);
    };


    // Code for JXA Context----------------------------------------------------

    // Using JXA to url-encode and then run the OmniJS code:

    // show :: a -> String
    function show(x) {
        return JSON.stringify(x, null, 2);
    };

    var a = Application("OmniGraffle"), // This was originally current application, but that's gonna be a bit arbitrary...
        sa = (a.includeStandardAdditions = true, a),

        // Javascript can convert a function to a source code string ...
        strCode = '(' + main.toString() + ')(' + show(dctOptions) + ')',
        strPrefix = 'omnigraffle:///omnijs-run?script=',

        // URL-encode the omniJS source code
        strOmniJSURL = strPrefix + encodeURIComponent(strCode);

    // Make sure that there is an active document in OmniGraffle 7.3 test
    var og = Application('OmniGraffle'),
        ds = og.documents,
        d = ds.length > 0 ? ds.at(0) : ds.push(og.Document());

    // Run the omniJS url
    og.activate();
    sa.openLocation(strOmniJSURL);

    // Copy and return the plain text of the OmniJS code for visual checking
    // sa.setTheClipboardTo(strCode);
    return strCode;
})();