Tinderbox Forum

JXA: need help with a few things

PS You can certainly skip the 'use strict'; incantation, but if you do, the error messages that you are shown will be less informative, and you will be left more puzzled if anything goes unexpectedly.

Your script lets Tinderbox panic. Is there something missing? Perhaps because of the Objective-C part? Do you need to import anything?

Ah, and one thing, that happened: I had Test.tbx already open and another document too, and the new note was written to the wrong document. So how could you set the focus to the right document?

This is really cool!

1 Like

We can specify a document by name:

tinderbox8.documents['test.tbx'].notes.push(newNote)

(See in full below)

Tell me more about the ‘panic’ – what error were you getting ?

(I’m sure you’ve checked for the most common problem in these contexts, which often affects me too – a copy paste which has accidentally dropped some tiny part from start or end of the posted script)

What version of Tbx and macOS are you running ?

This works here:


(() => {
    'use strict';

    const main = () => {

        // DECLARATIONS
        const
            tinderbox8 = Application('Tinderbox 8'),

            // '~'' expanded to full path.
            fp = filePath('~/Documents/test.tbx'),

            newNote = new tinderbox8.Note({
                name: 'Some title for a new note'
            });

        // EFFECTS
        tinderbox8.open(fp);
        tinderbox8.activate();
        tinderbox8.documents['test.tbx'].notes.push(newNote);

        // RETURN VALUE
        return newNote.name();
    };

    // GENERIC FUNCTIONS ----------------------------
    // https://github.com/RobTrew/prelude-jxa

    // filePath :: String -> FilePath
    const filePath = s =>
        ObjC.unwrap(ObjC.wrap(s)
            .stringByStandardizingPath);

    // CALL MAIN FUNCTION
    return main();
})();

The good old spinning pizza…
Event: hang

Mac OS X 10.14.5 (Build 18F132)
8.0.7 (b391)

And still with the second version of the script, and no lines missing ?

Hard to reproduce here. The trick is probably to comment most of it out, see how much, if anything, you can run of the opening lines without triggering and then expand to the first point where a problem occurs.

(if you can get a system log with relevant looking entries that might yield a clue)

(I’m running the same TBX as you, on macOS 10.14.6, but I don’t think that the OS version is likely to be relevant).

PS is your test.tbx large ? I wondered if we were catching it mid load, before it was able to respond to the API. Could be that we need to ensure that the file is fully parsed before moving on to the note creation and its addition to the notes collection.

(Mine is just an empty file)

By the way: 8.0.7 is a backstage build; we generally don’t talk about those on the main forum, as that can confuse people. No harm here, though.

https://www.eastgate.com/Tinderbox/Backstage.html

1 Like

It was indeed an issue of the Backstage version.
Sorry for the confusion… (@all, who are confused… I was not aware of this, as I mostly only use the latest version)

I think the hang occurs only in an unreleased test version; we’ll watch out for it.

@ComplexPoint: Do you have an idea, how this can be achieved?

I think you should replace

    tinderbox8.documents['xsmart'].notes.push(newNote);

with

   tinderbox8.documents['xsmart'].unshift(newNote);

But it’s been a while since I’ve used Javascript for anything like this.

That was my first idea, but somehow didn’t do the trick.

The thing to be aware of with collections like notes, is that Apple has created some syntactic sugar to make them look a little like JS arrays, but they are really osascript objects.

documents[0] gets pre-preprocessed to the real underlying
documents.at(0)

and
documents['text.tbx'] gets rewritten to
documents.byName('text.tbx')

before the JS interpreter itself actually sees them.

(I personally just use .at(n) and .byName(nameString), finding them slightly less confusing, and even fractionally faster at the last time of testing, though not perceptibly)

Meanwhile the .push and .unshift methods on that object are not really the JS Array methods which they look like, and don’t behave the same way.

We can obtain an actual Array of note values by writing:

documents['text.tbx'].byName('text.tbx').notes()

The trailling ( ) there creates an array. Without it, a plain

documents['text.tbx'].byName('text.tbx').notes

Is a reference to a function object.

(Manipulating an Array of note values, doesn’t however, make any changes to the order of the actual collection of notes in the app)

The note moving pattern is limited, as far as I can see, (in AS and JS) to moving an item into a new container.

So, for example, we could create a new note (the special collection.push() method always appends), and then move it from the end of its current container to become a child of some other note.

Here, we move the freshly created note to become a child of the first note in the document:

(() => {
    'use strict';

    const main = () => {

        // DECLARATIONS
        const
            tinderbox8 = Application('Tinderbox 8'),

            // '~'' expanded to full path.
            fp = filePath('~/Documents/test.tbx'),
            newNote = new tinderbox8.Note({
                name: 'an additional note of some kind'
            });

        // EFFECTS
        tinderbox8.open(fp);
        tinderbox8.activate();

        const
            doc = tinderbox8.documents.byName('test.tbx'),
            notes = doc.notes; // Collection reference, not a JS array.

        notes.push(newNote); // A special 'push', not the Array.push() method.
        tinderbox8.move(
            notes.at(-1), {
                to: notes.at(0)
            }
        );
    };

    // GENERIC FUNCTIONS ----------------------------
    // https://github.com/RobTrew/prelude-jxa

    // filePath :: String -> FilePath
    const filePath = s =>
        ObjC.unwrap(ObjC.wrap(s)
            .stringByStandardizingPath);

    // CALL MAIN FUNCTION
    return main();
})();

Sounds a little bit strange. That would mean, that it is really not possible to move the notes around in the top level? But only move them to another note as a child?

It may be that I just haven’t been a great mover of things and haven’t properly explored.

Anything that is possible in AppleScript will be possible in JS - any AppleScripters here who have experimented with note moving ?

Conceivable I think, that the move method of the osascript interface to Tbx8 is not yet fully implemented.

Putting JS aside for the moment, if I write this AppleScript for OmniOutliner, for example:

tell application "OmniOutliner"
    tell front document
        set oRow to make new row with properties {topic:"Epsilon"}
        move oRow to before first row
    end tell
end tell

The new “Epsilon” row becomes the first child of the document.

If, however, I write the same code for Tinderbox 8, the new note becomes the child, rather than preceding sibling, of the first existing note in the document.

tell application "Tinderbox 8"
    tell front document
        set oNote to make new note with properties {name:"Epsilon"}
        move oNote to before first note
    end tell
end tell

Any thoughts, @eastgate ?

1 Like

Ah, another machine seems to have logged me in, above, with the wrong credentials. Apologies, I will try to delete them.

The question would perhaps also be, what is possible with this “array-like” osascript object? What methods can be applied to it? Is this kind of array or object described anywhere? I could not find anything so far.

The basic reference is this:

https://developer.apple.com/library/archive/releasenotes/InterapplicationCommunication/RN-JavaScriptForAutomation/Articles/OSX10-10.html#//apple_ref/doc/uid/TP40014508-CH109-SW1

‘Element arrays’ section, in particular.

A slightly misleading name, but I think the intention was to adopt idioms that might look familiar to existing users of JS

Not too much information…