MacOS – Sharing multiple files on iCloud by using System Events in Applescript: How to intercept an option

applescriptautomatoricloudmacos

I am trying to share a folder with many Numbers files with iCloud, by sharing each file with an AppleScript and saving the path of each shared file so that I can send it to my collaborators. To do that, I use System Events. I got to the point in which I can share the files, but I cannot do something really simple.

By default, when you share a file Numbers gives you the "Mail" option by default in the "Invite with…" . There is also an option "Copy link". If I find a way to select that option, I can get then everything else working. However, despite my many attempts, I could find no way to tell System Events to change that default selection. Yet I can see what syntax Automator uses for the very same action, but when I copy that syntax into Script Editor, the action is not executed.

If you want to understand what the problem is, assuming that you have a 'test.numbers' file into your Numbers folder of your iCloud disk, the following script will share that file (paste it into the Script Editor app):

=====

    tell application "Finder"
        open POSIX file "/Users/[
   XXXPUT HERE YOUR USER NAME
   ]/Library/Mobile Documents/com~apple~Numbers/Documents/test.numbers"

        end tell
    delay 2
    tell application "System Events"
        tell process "Numbers"
            delay 1
            tell menu bar 1
                tell menu bar item "Share"
                    tell menu "Share"
                        delay 1
                        click menu item "Share Link via iCloud…"
                        delay 1
                    end tell
                end tell
            end tell
            click button "Share Spreadsheet" of UI element 1 of sheet 1 of window "test"
            delay 5
        end tell
        delay 5
        tell process "Numbers"
            tell menu bar 1
                tell menu bar item "Numbers"
                    tell menu "Numbers"
                        delay 1
                        click menu item "Quit Numbers"
                    end tell
                end tell
            end tell
        end tell
    end tell

=====

However, I found no way to do the simple extra step of changing the default value of mailing the link (you will see that the script paste the link into a message.

Does anybody have any clue as to how to achieve that? I tried the following possibilities, from a call to "System Events":
–click image 1 of UI element 3 of row 1 of scroll area 1 of UI element 1 of sheet 1 of window "test" of application process "Numbers"
–click button "Copy link" of row 1 of scroll area 1 of UI element 1 of sheet 1 of window "test" of application process "Numbers"
–click UI element 3 of row 1 of scroll area 1 of UI element 1 of sheet 1 of window "test" of application process "Numbers"

When the script does not complain, the action is simply not executed.
For clarity, I am talking about selecting the option "Copy Link" in the pasted image:

Default Share Link Dropdown Window

Any suggestion is welcome.
Thanks,

(Using OSX El Capitain 10.11.5)

Best Answer

OK so I answer my own question. It is possible to do what I wanted, although I did not find a satisfactory solution.

The short answer is: I could find no way to use applescript with the direct manipulation of the graphical interface (eg. clicks). I did find a way by using key alternatives. To do the exact bit of work that I needed, the following sequence will do:

-- after opening the document in Numbers, open the share window:

tell application "System Events"
    tell process "Numbers"
        delay 1
        tell menu bar 1
            tell menu bar item "Share"
                tell menu "Share"

                    delay 1
                    click menu item "Share Link via iCloud…"

                end tell

            end tell
        end tell

    end tell

-- once the share dropdown window is open, use the following key combination

tell application "System Events"
--add tabs

    delay 1
    key code 48
    delay 1
    key code 48
    delay 1
    -- use arrows to move to the right part of the 'Share' window
    key code 124
    delay 1
    key code 124

    delay 3
    --  click return
    key code 36

    delay 8
    -- save the file and close it
    keystroke "s" using {command down}
    delay 4
    keystroke "w" using {command down}

The long answer is: it is a pain in the neck for a series of reasons.

First, when you create a Numbers file, it is a simple file. However, when it is shared, or when it is being saved in iCloud, it becomes a package. Applescript sees packages as folders, so you have to do some check before doing anything as to whether what you are dealing with is a folder or a package. Then you can go on to the sharing operations.

Now, I found NO principle way to intercept when exactly a file becomes a package. That is, when you open a Numbers file and ask it to be shared, you will see that Numbers gives you a "preparing the document to share" message. This, I found, is when the file is transformed into a package. There is a property that one can use in order to check if a given path corresponds to a package or a single file: one could loop while (package folder of the item_info is false) and then continue, but this property becomes set as true well before Numbers has finished its own "preparing the document to share" work. So I could only guess when I can continue and go to the sharing part of the script. I put a rough delay of 30 seconds when a file is not yet a package, which should give plenty of time for Numbers to finish its transformations of the file to share:

if (this_package_folder is false) and (this_extension is in the extension_list) then
    delay 30
end if

Second, you must be on a good network, so that all operations related to Numbers in iCloud can be done smoothly -- otherwise, iCloud will give you error messages that will block the execution of the script

Third, you have to take care of the .DS_Store files and other files that may be inside the folder where you put your Numbers documents to be shared.

Fourth, if you want to identify where the iCloud folder with the documents to be shared is, from inside AppleScript you won't see it as you see it from the finder (i.e., in the iCloud Drive), but you will have to look for it in /yourUser/Library/Mobile Documents/iCloud Drive/yourfolder.

With all these caveats, here is the script that I am using now. In my system, it works. It assumes several things:

  1. there is a folder in your iCloud where your Numbers documents are
  2. you have a file where you want to save the paths of the files that will be shared, so that you know the paths that you have to communicate to those with who you want to share your files. In my case, I use a Pages document.
  3. the files to be shared ARE NOT already shared. Otherwise, the script will give errors.
  4. you don't care about errors and style. The script has no error checks. I am not a programmer.

The script will ask you to first identify the folder with the documents to be shared, then the Pages file where you want to save the paths of the shared documents, and then will open the documents to be shared one by one, will share them, will save them, will copy their path to the Pages document that you selected, and finally will quit Numbers and Pages. Give plenty of time for the script to execute and don't interfere with it. Notice that when you open each Numbers file, you can modify the script so that you insert specific operations that you want to be done on your files, always with the same technique (for example, in my case I need to find a cell, find a value, copy it somewhere else and save it. This part of the procedure is not in the script below. You can add whatever your fantasy leads you to invent as contorted and complicated operations).

Now, if somebody finds a way to REVERSE the operation, unsharing the shared files, and especially, a way to tell if a file is ALREADY shared or not, so that the script acquires generality....

I paste the script below.

-- Beginning of the script
global f

property extension_list : {"numbers"}
tell application "Finder"
set source_folder to choose folder with prompt "Please select directory."
set posixSource_Folder to POSIX path of source_folder
tell application "System Events"

    set these_items to POSIX path of disk items of folder posixSource_Folder
end tell

my createList(these_items)
end tell

on createList(these_items)
tell application "System Events"
    tell application "Finder"
        set f to (choose file with prompt "Choose a file where to store the paths")
    end tell
end tell
set posixF to POSIX path of f
delay 2
tell application "Finder" to open file f
delay 1
repeat with i from 1 to the count of these_items
    set this_item to item i of these_items

    set the item_info to info for this_item
    set this_extension to the name extension of item_info
    if folder of the item_info is true and (package folder of the item_info is false) and (this_extension is not in the extension_list) then

        process_folder(this_item)

    else
        if (this_extension is in the extension_list) then
            process_item(this_item)

        end if
    end if
end repeat
close_files()
end createList

-- this sub-routine processes folders 
on process_folder(this_folder)
-- set these_items to list folder this_folder without invisibles
set posix_this_folder to POSIX path of this_folder
tell application "System Events"

    set these_items to POSIX path of disk items of folder posix_this_folder
end tell
repeat with i from 1 to the count of these_items
    --set this_item to alias ((this_folder as Unicode text) & (item i of these_items))
    set the item_info to info for this_item
    set this_extension to the name extension of item_info
    --if folder of the item_info is true and (this_extension is not in the extension_list) then
    if folder of the item_info is true and (package folder of the item_info is false) and (this_extension is not in the extension_list) then

        process_folder(this_item)
    else
        if (package folder of the item_info is true) and (this_extension is in the extension_list) and (alias of the item_info is false) then
            process_item(this_item)

        end if


    end if
   end repeat
end process_folder

-- this sub-routine processes files 

on process_item(this_item)
set the item_info to info for this_item
set this_extension to the name extension of item_info
set this_package_folder to the package folder of item_info
set Posix_Item to POSIX path of this_item

set Posix_File to POSIX file Posix_Item
delay 1
--opening the Numbers file
tell application "Finder" to open Posix_File
delay 3
-- going to Numbers and making the file shared

tell application "System Events"
    tell process "Numbers"
        delay 1
        tell menu bar 1
            tell menu bar item "Share"
                tell menu "Share"

                    delay 1
                    click menu item "Share Link via iCloud…"

                end tell

            end tell
        end tell

    end tell

    -- extra time allowed for non packages

    delay 3
end tell
if (this_package_folder is false) and (this_extension is in the extension_list) then

    delay 30
end if


--tabs
tell application "System Events"
    delay 1
    key code 48
    delay 1
    key code 48
    delay 1
    -- arrows
    key code 124
    delay 1
    key code 124

    delay 3
    --  returns
    key code 36

    -- leave some time for Numbers to actually share the file. Maybe you need more time for your system.
    delay 8

    -- saving and closing documents
    keystroke "s" using {command down}
    delay 4
    keystroke "w" using {command down}

    -- Now returning to the file where the paths have to be pasted
    tell application "Finder" to open file f
    delay 2
    -- pasting the local Unix path
    keystroke "v" using {command down}
    delay 1
    key code 48

    delay 2
    -- pasting the iCloud remote path of the shared document
    set the clipboard to Posix_Item
    delay 1
    keystroke "v" using {command down}
    delay 1
    key code 48
    key code 36

    delay 1
    keystroke "s" using {command down}
end tell

end process_item


--closing files

on close_files()
tell application "System Events"
    tell process "Numbers"
        tell menu bar 1
            tell menu bar item "Numbers"
                tell menu "Numbers"

                    delay 1
                    click menu item "Quit Numbers"
                end tell
            end tell
        end tell
    end tell


    tell application "Finder" to open file f
    delay 2
    keystroke "q" using {command down}
    delay 1
end tell
end close_files
-- end of the script