Calling a script with an AppleScript

Tagged: 

Viewing 23 reply threads
  • Author
    Posts
  • October 29, 2019 at 12:59 PM #37545

    Martin Inchley
    Participant

    Having checked out TapForms’ AppleScript dictionary, I wrote the following:

    tell application “Tap Forms Mac 5”
    run form script named “Composite script” in form “New gig database”
    end tell

    The script compiles OK, but when I run it I get an error: “Tap Forms Mac 5 got an error: Can’t get form script \”Composite script\”.” number -1728 from form script “Composite script”.

    The TapForms form script “Composite script” itself is alive and well and functioning fine in the database, so it’s likely to be an issue with how instructions work. I couldn’t find any examples of AppleScript calling a TapForms script, neither in the forum nor in the wider net. Anyone know how to do this?

    November 1, 2019 at 9:47 AM #37650

    Martin Inchley
    Participant

    Following an email exchange with Brendan, and some further unsuccessful experimenting, I tried to use AppleScript to open a script in a new, absolutely minimal database created for my other current query in this forum about scripting time data:

    Form Script “New Script” is:

    function New_Script() {
    
    	var time_id = 'fld-33fcface42864bf3801d7bf521c14e7f';
    	var thisTime = record.getFieldValue('fld-33fcface42864bf3801d7bf521c14e7f');
    	console.log(thisTime)
    
    }
    
    New_Script();

    When run, it puts a time value into the console (albeit, as discussed in the other thread, an hour earlier than the value in the originating field).

    However, when I use this AppleScript to call it:

    tell application "Tap Forms Mac 5"
    	
    	open "/Users/martin/Library/Containers/com.tapzapp.tapforms-mac/Data/Documents/Time testing.tapforms"
    	set doc to document "Time testing.tapforms"
    	run doc script named "New Script" in form "New Form"
    	
    end tell

    I get the following console message: “New Script: TypeError: undefined is not an object (evaluating ‘record.getFieldValue’), column:23, line:4”. Column 23 of line 4 is the dot in record.getFieldValue.

    I suppose this is an improvement on nothing happening (!), but I don’t understand why this should happen.

    November 1, 2019 at 10:27 AM #37652

    Sam Moffatt
    Participant

    Form scripts can be executed without a record being selected. What you’re running into is that there is no record selected and as such record is undefined.

    It’s more likely to be seen on iOS where you can run form scripts from the list view without anything selected but as you’ve found out it is also achievable on the desktop as well, just less likely.

    November 1, 2019 at 11:15 AM #37659

    Martin Inchley
    Participant

    Thanks, Sam.

    Can you give me a syntax in AppleScript or JavaScript for selecting a record?

    November 1, 2019 at 12:02 PM #37661

    Daniel Leu
    Participant

    I’m wondering if you have to select a form from AppleScript first? But I don’t know how the syntax would look like.

    To get a valid record, the question is, which record are you looking for? The first one, a matching one, a new one?

    Here is the concept to get to the records without having a valid form. I assume that this is the case for your since you only open a document with AppleScript.

    var records = document.getFormNamed('form name').getRecords(); // get all records of given form.
    
    // loop over all records
    for (record of records){
       console.log(record.getFieldValue(time_id));
    }
    November 4, 2019 at 10:49 AM #37755

    Martin Inchley
    Participant

    I appreciate the help, but this is proving really problematic. If the record that I want to work with is the active record in the form, why does TapForms think the record is “undefined”, just because I’ve called the script from an AppleScript? The script works when I just run it from within TapForms, but I want a simple way to successfully call from AppleScript a script that will act with the current record.

    In addition – testing out functions from the TapForms JavaScript API web page, I edited my script to read simply:

    function New_Script() {
    	form.selectRecord()
    }
    
    New_Script();

    Every time I run this script by clicking the “Run” arrow, TapForms crashes.

    November 4, 2019 at 12:05 PM #37758

    Daniel Leu
    Participant

    Not nice that TapForms crashes, but form.selectRecord() expects an argument: form.selectRecord(someRecord);

    November 4, 2019 at 12:11 PM #37759

    Martin Inchley
    Participant

    Tanks, Daniel. I take it that a record ID would do it, but I was hoping for a simpler method, such as a current Record identifier. I can’t see anything on the API webpage about referencing the current record. Am I missing something?

    November 4, 2019 at 1:18 PM #37760

    Daniel Leu
    Participant

    I take it that a record ID would do it, but I was hoping for a simpler method, such as a current Record identifier.

    According to the documentation, the argument is a record and not a record ID.

    You get to the current record by just using record. Eg, record.getFieldValue(fieldId).

    You might want to check that record is indeed defined: if (record) console.log(record.getFieldValue(fieldId));

    November 4, 2019 at 5:31 PM #37762

    Sam Moffatt
    Participant

    There is a form.getRecordWithId(‘rec-1234’) that you can use to get a record by ID and then you could use that record with selectRecord at that point.

    November 5, 2019 at 5:38 AM #37789

    Martin Inchley
    Participant

    Thank you, Sam. So I found that this code jumps me to the specified record:

    var thisRec = form.getRecordWithId('rec-93d0352d75c64a638dced9515827ac95');
    form.selectRecord(thisRec)

    Great! But my need is to get TapForms to recognise that the current record is “selected” when I call a script from AppleScript. So I tried:

    var thisRecID = record.getId()
    var thisRec = form.getRecordWithId(thisRecID)
    form.selectRecord(thisRec)

    Running this script does nothing visible, of course, because it tells TF to go to the current record. My hope is that it would tell TF that the current record is indeed selected. But when I call this script from AppleScript, I get the same complaint in the console:

    “Record ID testing: TypeError: undefined is not an object (evaluating ‘record.getId’), column:23, line:1”

    I.e. it simply does not recognise “record” in line 1 as referring to the current record.

    Any more ideas?

    November 6, 2019 at 2:16 AM #37845

    Brendan
    Keymaster

    I just fixed the crash error for this. It was because I was adding the record ID to a dictionary and since the record was nil, that causes a crash. You can’t add a nil value to a dictionary. At least not in the way I was constructing the dictionary.

    November 6, 2019 at 2:33 AM #37846

    Brendan
    Keymaster

    In the context of AppleScript, there is no current record so you have to select one first. You can’t call record.getId() because there is no current record.

    The function that handles the AppleScript command will take 3 arguments. A form, a script, and a search.

    - (void)handleRunScriptCommand:(NSScriptCommand *)command {
    	NSString *formName = command.evaluatedArguments[@"form"];
    	NSString *scriptName = command.evaluatedArguments[@"script"];
    	NSString *searchName = command.evaluatedArguments[@"search"];
     ... do stuff
    }

    Once it has all that stuff, it runs the script:

    [self runScript:form search:(TFSearch *)search record:nil script:script];

    Passing in nil for the record because there’s no current record.

    The reason for this is the script is being run outside the context of the state of the user interface. So Tap Forms doesn’t have the current record. However, I could probably modify it so that it does pass in the current record to that call. And I’ve just done that.

    November 7, 2019 at 5:53 AM #37901

    Martin Inchley
    Participant

    Brendan, can you think of a workaround while we wait for the next build?

    November 7, 2019 at 12:31 PM #37905

    Brendan
    Keymaster

    Hi Martin,

    You’ll just have to get the specific record first in the script:

    var thisRec = form.getRecordWithId('rec-93d0352d75c64a638dced9515827ac95');

    November 8, 2019 at 7:27 AM #37917

    Martin Inchley
    Participant

    Isn’t that circular? I would need to know the record ID for the current record – but there’s no way of knowing what that is. I can only use this snippet if I know in advance which record I want to target.

    I want to be working on a record in TF, and then invoke a workflow in Automator/AppleScript which involves a TF script referencing the TF record I’ve been working with.

    November 8, 2019 at 8:53 AM #37918

    Daniel Leu
    Participant

    How about having one additional TF script that you launch before you start your Automator/AppleScript flow? In this script, you would store record.getId() in a dedicated form ‘workaround’ with one field: currentRecordId. Then in your TF script called via AppleScript, first you would restore the current record based on currentRecordId fetched from the ‘workaround’ form.

    Again, this is only a workaround until TF sets record when being called from an external AppleScript.

    November 8, 2019 at 7:31 PM #37935

    Sam Moffatt
    Participant

    I had a play with this and decided to use the new 5.3.7 clipboard support. I broke it up into three scripts: a launcher form script called Open AppleScript, the AppleScript itself and then a Land AppleScript to print the record ID.

    I used openUrl and this seemed to work ok. I also added a file attachment to a form and then attached the app to it to see if this would get around the Mac file limitation. This seemed to work for me but I didn’t try a fully sandboxed MAS version.

    The AppleScript I converted into an application to let Tap Forms launch it. This seemed to work fine. I modified your script to not re-open the same document since in this case it was open already to start the script and opening the document again was causing TF to open the document twice.

    The last bit just validates that the clipboard is fine. Obviously if you use the clipboard along the way it won’t work properly but I think for this use case maybe it’d be ok? Even if you did use the clipboard in your ApplesScript, you could format it in such a way that the Tap Forms script could process it and make sense of it.

    Of course we could just wait for the next Tap Forms release where it’s fixed but where’s the fun in that?

    The Open AppleScript:

    Utils.copyTextToClipboard(record.getId());
    Utils.openUrl('file:///Users/pasamio/Documents/argv.app/');
    

    The AppleScript:

    tell application "Tap Forms Mac 5"
    	set theDialogText to "Running AppleScript!"
    	display dialog theDialogText
    	set doc to document "Test-TemplateImport.tapforms"
    	run doc script named "Land AppleScript" in form "AppleScript"
    end tell

    The Land AppleScript form script:

    Utils.alertWithMessage('Remote ID', Utils.copyTextFromClipboard());
    
    November 8, 2019 at 11:35 PM #37943

    Brendan
    Keymaster

    The latest beta already has support for giving you access to the current record.

    @Martin, let me know if you’d like access to the betas. Email me at support@tapforms.com

    November 9, 2019 at 5:44 AM #37954

    Martin Inchley
    Participant

    @Sam I re-created your scenario with my own file names in place. The AppleScript triggers <Land AppleScript> fine. However, when I called the Run AppleScript script to start the process, I got an error from the Mac: ‘The application “Tap Forms Mac 5” does not have permission to open “(null).” ‘ Do you know where the permissions for that are set?

    November 9, 2019 at 10:55 AM #37960

    Sam Moffatt
    Participant

    I used a file attachment field to get the file browser to prompt and select the file. Once you’ve done that, I think Tap Forms should have access to the file.

    So create a form somewhere with a file attachment field, add to it your AppleScript app and then you should be able to execute it.

    Also getting access to the latest beta should help you as well.

    November 9, 2019 at 11:18 AM #37963

    Martin Inchley
    Participant

    1. Is there any info anywhere about getting a script to target a file in a file attachment field? The TapForms manual has a rather minimalist approach.
    2. I’ve got the AppleScript app into the file, plus a PDF. Double-clicking the PDF runs Preview and brings up the file. Double-clicking the AppleScript app does nothing observable.

    November 9, 2019 at 12:23 PM #37964

    Sam Moffatt
    Participant

    Once I attached the app into the file attachment field, it successfully execute the app using my script. This wasn’t on the MAS version though, so it’s possible there’s some extra quirks there. Let me find that and see if I can get it to work there.

    1. Open app
    2. Ran script, got unable to run “null” error.

    3. Added target app to file attachment field.
    4. Ran script again, seemed to work.

    It did ask to be able to control Tap Forms though, I did a manual Gatekeeper exception on the command line and that seemed to go away: spctl --add ~/Documents/argv.app/

    The reason to add the files to the file attachment field is to bypass the sandbox security. Once an app on MacOS been granted access to a file outside of it’s sandbox, it’s allowed to access it later. That needs to happen through the system controlled file picker dialog which is why we use the file attachment pathway. You don’t need to run the script from there but for each new Mac you need to go through the same process to give Tap Forms access to the file.

    Note: I’m on Mojave, it’s possible if you’re on Catalina they’ve tightened it up more.

    Attachments:
    You must be logged in to view attached files.
    November 9, 2019 at 12:45 PM #37966

    Martin Inchley
    Participant

    Thanks for the tutorial, Sam! Call me old-fashioned, but I think it’s bizarre to put the app in the field, but not have to make any reference to it being there for the app to run!

    Anyway, I did what you did, with the same result. But I’m not going to start invoking the command line – the development I’m trying to do here is meant for use by my son and his band’s manager. The motto is KISS!

    November 10, 2019 at 1:26 AM #37978

    Sam Moffatt
    Participant

    It’s a little different for sure, it’s an attempt to bypass the MacOS restrictions though I guess it’s not working for you. In any case the next version will fix the record selection quirk so that means calling into Tap Forms will work for your use case. Apple keep locking things down which makes some of these more advanced scripting features a little harder to implement each year.

Viewing 23 reply threads

You must be logged in to reply to this topic.