×

FilePicker

A FilePicker is the user-facing system interface for selecting files or folders. The items chosen by the user are returned to the Omni Automation script as an array of URLs to the chosen items. The FilePicker class is supported by all Omni Automation applications on both iOS and macOS.

Constructors

An instance of the FilePicker class is created using the standard new constructor without any initial provided parameters.

New FilePicker Instance


var picker = new FilePicker()

Instance Properties

Control of the selection options for a FilePicker instance is accomplished by setting the values of the following properties:

For example, the following script will create a FilePicker instance that will only allow the selection of a single text file:

Set Properties of New FilePicker


var picker = new FilePicker() picker.folders = false picker.multiple = false picker.types = [FileType.plainText]

Instance Methods

Once an instance of the FilePicker class has been created, it can be displayed to the user by calling the show() method on the instance.

Create and Display FilePicker


var picker = new FilePicker() picker.folders = false picker.multiple = false picker.types = [FileType.plainText] var pickerPromise = picker.show()

Depending upon which operating system is used by the device running the script, the file picker will be presented as either a sheet (macOS 10.5) or an overlay dialog (iOS, macOS 11+).

Alternate Plain Text Type


var aType = new FileType("public.plain-text") var picker = new FilePicker() picker.folders = false picker.multiple = false picker.types = [aType] pickerPromise = picker.show()

Processing the FilePicker Results

When a file picker dialog is displayed, a JavaScript Promise object is returned to the script. This promise represents either the completion or cancellation of the user’s interaction with the file picker dialog, and if successful will contain an array of URL references to the items chosen by the user.

The Promise object can be processed by the script with standalone functions that process its success or cancelation, or through the inline appending of the then(…) function of the Promise class to the show() command (of the FilePicker class) to act as a receiver for the passed promise object.

In the following example of the inline technique, the call-back function within the then(…) method is passed the result of the successful completion of the picker dialog, which is an array of URLs to the chosen items. Note that the successful picker result is always an array of URL objects even if only a single item was chosen.

Choose and Import Text from File
 

var picker = new FilePicker() picker.folders = false picker.multiple = false picker.types = [FileType.plainText] picker.show().then(urlsArray => { var aURL = urlsArray[0] aURL.fetch(data => { console.log(data.toString()) }) })

Optionally, you may call the then() function on the stored Promise object to retrieve the chosen file(s), and to respond with other actions should the user choose to cancel the FilePicker:

The FilePicker Promise Object


var picker = new FilePicker() picker.folders = false picker.multiple = false picker.types = [FileType.plainText] var pickerPromise = picker.show() pickerPromise.then(function(urlsArray){ var fileURL = urlsArray[0] console.log(fileURL.string) }) pickerPromise.catch(err =>{ console.log("picker cancelled", err.message) })

Here’s an example of using a file picker to select an open an existing OmniGraffle file and add a new canvas to it:

omnigraffle://localhost/omnijs-run?script=try%7Bvar%20picker%20%3D%20new%20FilePicker%28%29%0Apicker%2Efolders%20%3D%20false%0Apicker%2Emultiple%20%3D%20false%0AaFileType%20%3D%20new%20FileType%28%22com%2Eomnigroup%2Eomnigraffle%2Egraffle%22%29%0Apicker%2Etypes%20%3D%20%5BaFileType%5D%0ApickerPromise%20%3D%20picker%2Eshow%28%29%0A%0ApickerPromise%2Ethen%28function%28urlsArray%29%7B%0A%09fileURL%20%3D%20urlsArray%5B0%5D%0A%09app%2EopenDocument%28%0A%09%09document%2C%0A%09%09fileURL%2C%0A%09%09function%28doc%2CwasOpen%29%7B%0A%09%09%09cnvs%20%3D%20doc%2Eportfolio%2EaddCanvas%28%29%0A%09%09%7D%29%0A%7D%29%7Dcatch%28err%29%7Bconsole%2Elog%28err%29%7D
Choose and Open OmniGraffle Document
 

var picker = new FilePicker() picker.folders = false picker.multiple = false aFileType = new FileType("com.omnigroup.omnigraffle.graffle") picker.types = [aFileType] pickerPromise = picker.show() pickerPromise.then(function(urlsArray){ fileURL = urlsArray[0] app.openDocument( document, fileURL, function(doc,wasOpen){ cnvs = doc.portfolio.addCanvas() } ) })

 01  Create a new empty file picker object and store it in a variable.

 02-03  Set the properties of the new file picker.

 04  Create a new FileType instance of an OmniGraffle document.

 05  Assign the created file type as the value of the picker’s type property.

 06  Use the show(…) method of the FilePicker class to display the file picker dialog to the user. The result of this method is a new JavaScript Promise object that is stored in the variable: pickerPromise

 08-17  The successful promise is processed using the then(…) method whose call-back function is automatically passed an array of the chosen item URLs.

 09  A URL object is extracted from the URLs array passed by the promise as input to the call-back function.

 10-16  Use the openDocument(…) function of the Application class (passing in the URL to the chosen file) to open the file.

 13-15  The call-back function is passed as input a reference to the opened document.

 14  The document’s portfolio property is used to reference the document’s Portfolio object for calling the addCanvas() method in order to create a new canvas.

Create Image Data URL

This script example will create an HTML image data URL using the image data of the chosen PNG file. Image Data URLs do not link to files, but instead include the image data expressed as a base64 string.

The resulting image data URL will be logged to the console and copied to the clipboard, ready to paste into HTML content. IMPORTANT: Always choose VERY SMALL images, and be sure to set the values of the image width and height style properties!

<-- Here is an image displayed using an image data URL!

var picker = new FilePicker() picker.folders = false picker.multiple = false picker.types = [TypeIdentifier.png] picker.show().then(function(urlsArray){ var aURL = urlsArray[0] aURL.fetch(function(data){ var imageURL = "" console.log(imageURL) Pasteboard.general.string = imageURL new Alert("COMPLETED","URL code is on the clipboard.").show() }) })
Create Image Data URL from Chosen Image
  

var picker = new FilePicker() picker.folders = false picker.multiple = false picker.types = [TypeIdentifier.png] picker.show().then(function(urlsArray){ var aURL = urlsArray[0] aURL.fetch(function(data){ var imageURL = "<img style=\"width:auto;height:auto;\" src=\"data:image/png;base64," + data.toBase64() + "\">" console.log(imageURL) Pasteboard.general.string = imageURL new Alert("COMPLETED","URL code is on the clipboard.").show() }) })

Folder Picker

To create a FilePicker that selects a chosen folder, include the UTI for a folder AND set the value of the picker’s folders property to true. Here is an asynchronous example script that opens the selected folder:

Folder Picker


(async () => { var folderUTI = new TypeIdentifier("public.folder") var picker = new FilePicker() picker.multiple = false picker.folders = true picker.types = [folderUTI]; var urls = await picker.show(); urls[0].open() })().catch(err => { if(!err.message.includes("User cancelled")) { new Alert(err.name, err.message).show() } })

Using FilePicker with Plug-Ins

The use of a file picker can greatly enhance the usefulness of Omni Automation actions designed to import and integrate data or files into documents. For example, a file picker provides an excellent way for a user to select a text file whose contents are to be imported into a selected container or shape in OmniGraffle.

When integrating a file picker with an action, the use of the Promise object allows for independent handling of the promise success or cancellation events with the then(…) and cancel(…) instance functions of the Promise class.

You can use the following example action as a template for integration of a file picker into an Omni Automation action.

Import Text into Shape
 

// PLUG-IN METADATA (REQUIRED) /*{ "type": "action", "targets": ["omnigraffle"], "author": "Otto Automator", "identifier": "com.omni-automation.og.import-text-into-shape", "description": "Imports text from the chosen text file into the selected shape.", "label": "Import Text into Shape", "shortLabel": "Import Text" }*/ // MAIN FUNCTION (() => { // CREATE ACTION OBJECT var action = new PlugIn.Action(function(selection, sender){ var selectedShape = selection.solids[0] // CONSTRUCT THE PICKER var picker = new FilePicker() picker.folders = false picker.multiple = false picker.types = [FileType.plainText] // SHOW THE PICKER AND RETURN JAVASCRIPT PROMISE pickerPromise = picker.show() // PROCESS THE PICKER RESULTS pickerPromise.then(function(urlsArray){ // RETRIEVE CHOSEN FILE REFERENCE fileURL = urlsArray[0] // IMPORT DATA FROM CHOSEN FILE fileURL.fetch(function(data) { selectedShape.text = data.toString() }) }) // PROCESS PICKER CANCELLATION pickerPromise.catch(function(error){ console.log("picker cancelled", error) }) }) // VALIDATE DOCUMENT SELECTION action.validate = function(selection, sender){ return (selection.solids.length == 1 ? true:false) } // RETURN ACTION OBJECT return action })();

 02-10  The required metadata for the action file.

 12-52  The wrapping function that holds and executes the action.

 14-52  The new action instance with a call-back function that contains the executable code. By default, a reference to the current document selection is passed as input to the call-back function.

 45-47  The action validation function returns a boolean value based upon whether a single solid is selected in the document. If the validation value is true, then the action’s menu item becomes enabled in the application’s Automation menu.

 16  A reference to the selected graphic is stored in the variable: selectedShape

 19-22  a new FilePicker instance is created and its properties are set to allow the selection of only a single text file.

 25  The file picker is displayed to the user, resulting in a returned Promise object that gets stored in the variable: pickerPromise

 28-36  A successful completion of the picker dialog result in the then(…) function being called on the stored Promise object. By default, an array of URLs representing the user-selected items will be provided as input to the method’s call-back function.

 30  A reference to the sole selected item is stored in the variable: fileURL

 33-35  To retrieve the text contents of the chosen file, the fetch(…) method of the URL class is called upon the chosen file. The result of the fetching process will be the data from the file.

 34  The retrieved data is converted into a string using the standard toString() JavaScript method, and the resulting text is imported into the selected shape by setting the value of the shape’s text property to the converted data string.

 39-41  Should the picker dialog be cancelled, the catch(…) function is called on the Promise instance, allowing the script to perform any cleanup, logging, or handling of the error that may be necessary.

 50  The completed action object is returned to the wrapping function, which is then called and executed on line  52 

Picker Prompt

In recent Omni application updates, the message property has been added to the FilePicker class to provide the ability to display a prompt in the macOS file picker dialog. Since iOS does not support the inclusion of a prompt in the iOS file picker, the following script example shows how to use an alert to provide similar prompt functionality on iOS:

omnigraffle://localhost/omnijs-run?script=try%7Bvar%20picker%20%3D%20new%20FilePicker%28%29%0Apicker%2Efolders%20%3D%20false%0Apicker%2Emultiple%20%3D%20false%0Apicker%2Etypes%20%3D%20%5BFileType%2EplainText%5D%0A%2F%2F%20DECLARE%20THE%20PROMISE%20VARIABLE%0Avar%20pickerPromise%0A%2F%2F%20CHECK%20PLATFORM%0Aif%28app%2EplatformName%20%3D%3D%3D%20%22iOS%22%29%7B%0A%09msg%20%3D%20%22Tap%20%E2%80%9DContinue%E2%80%9D%20and%20choose%20a%20text%20file%20from%20the%20forthcoming%20file%20picker%3A%22%0A%09var%20alert%20%3D%20new%20Alert%28%22Select%20File%22%2C%20msg%29%0A%09alert%2EaddOption%28%22Continue%22%29%0A%09alert%2Eshow%28function%28result%29%7B%0A%09%09pickerPromise%20%3D%20picker%2Eshow%28%29%0A%09%7D%29%0A%7D%20else%20if%20%28app%2EplatformName%20%3D%3D%3D%20%22macOS%22%29%7B%0A%09picker%2Emessage%20%3D%20%22Choose%20the%20text%20file%20to%20import%3A%22%0A%09pickerPromise%20%3D%20picker%2Eshow%28%29%0A%7D%0A%2F%2F%20READ%20CONTENTS%20OF%20THE%20CHOSEN%20TEXT%20FILE%0ApickerPromise%2Ethen%28function%28urls%29%7B%0A%09url%20%3D%20urls%5B0%5D%0A%09url%2Efetch%28function%28data%29%7B%0A%09%09console%2Elog%28data%2EtoString%28%29%29%0A%09%7D%29%0A%7D%29%7Dcatch%28err%29%7Bconsole%2Elog%28err%29%7D
omnioutliner://localhost/omnijs-run?script=try%7Bvar%20picker%20%3D%20new%20FilePicker%28%29%0Apicker%2Efolders%20%3D%20false%0Apicker%2Emultiple%20%3D%20false%0Apicker%2Etypes%20%3D%20%5BFileType%2EplainText%5D%0A%2F%2F%20DECLARE%20THE%20PROMISE%20VARIABLE%0Avar%20pickerPromise%0A%2F%2F%20CHECK%20PLATFORM%0Aif%28app%2EplatformName%20%3D%3D%3D%20%22iOS%22%29%7B%0A%09msg%20%3D%20%22Tap%20%E2%80%9DContinue%E2%80%9D%20and%20choose%20a%20text%20file%20from%20the%20forthcoming%20file%20picker%3A%22%0A%09var%20alert%20%3D%20new%20Alert%28%22Select%20File%22%2C%20msg%29%0A%09alert%2EaddOption%28%22Continue%22%29%0A%09alert%2Eshow%28function%28result%29%7B%0A%09%09pickerPromise%20%3D%20picker%2Eshow%28%29%0A%09%7D%29%0A%7D%20else%20if%20%28app%2EplatformName%20%3D%3D%3D%20%22macOS%22%29%7B%0A%09picker%2Emessage%20%3D%20%22Choose%20the%20text%20file%20to%20import%3A%22%0A%09pickerPromise%20%3D%20picker%2Eshow%28%29%0A%7D%0A%2F%2F%20READ%20CONTENTS%20OF%20THE%20CHOSEN%20TEXT%20FILE%0ApickerPromise%2Ethen%28function%28urls%29%7B%0A%09url%20%3D%20urls%5B0%5D%0A%09url%2Efetch%28function%28data%29%7B%0A%09%09console%2Elog%28data%2EtoString%28%29%29%0A%09%7D%29%0A%7D%29%7Dcatch%28err%29%7Bconsole%2Elog%28err%29%7D
omnifocus://localhost/omnijs-run?script=try%7Bvar%20picker%20%3D%20new%20FilePicker%28%29%0Apicker%2Efolders%20%3D%20false%0Apicker%2Emultiple%20%3D%20false%0Apicker%2Etypes%20%3D%20%5BFileType%2EplainText%5D%0A%2F%2F%20DECLARE%20THE%20PROMISE%20VARIABLE%0Avar%20pickerPromise%0A%2F%2F%20CHECK%20PLATFORM%0Aif%28app%2EplatformName%20%3D%3D%3D%20%22iOS%22%29%7B%0A%09msg%20%3D%20%22Tap%20%E2%80%9DContinue%E2%80%9D%20and%20choose%20a%20text%20file%20from%20the%20forthcoming%20file%20picker%3A%22%0A%09var%20alert%20%3D%20new%20Alert%28%22Select%20File%22%2C%20msg%29%0A%09alert%2EaddOption%28%22Continue%22%29%0A%09alert%2Eshow%28function%28result%29%7B%0A%09%09pickerPromise%20%3D%20picker%2Eshow%28%29%0A%09%7D%29%0A%7D%20else%20if%20%28app%2EplatformName%20%3D%3D%3D%20%22macOS%22%29%7B%0A%09picker%2Emessage%20%3D%20%22Choose%20the%20text%20file%20to%20import%3A%22%0A%09pickerPromise%20%3D%20picker%2Eshow%28%29%0A%7D%0A%2F%2F%20READ%20CONTENTS%20OF%20THE%20CHOSEN%20TEXT%20FILE%0ApickerPromise%2Ethen%28function%28urls%29%7B%0A%09url%20%3D%20urls%5B0%5D%0A%09url%2Efetch%28function%28data%29%7B%0A%09%09console%2Elog%28data%2EtoString%28%29%29%0A%09%7D%29%0A%7D%29%7Dcatch%28err%29%7Bconsole%2Elog%28err%29%7D
omniplan://localhost/omnijs-run?script=try%7Bvar%20picker%20%3D%20new%20FilePicker%28%29%0Apicker%2Efolders%20%3D%20false%0Apicker%2Emultiple%20%3D%20false%0Apicker%2Etypes%20%3D%20%5BFileType%2EplainText%5D%0A%2F%2F%20DECLARE%20THE%20PROMISE%20VARIABLE%0Avar%20pickerPromise%0A%2F%2F%20CHECK%20PLATFORM%0Aif%28app%2EplatformName%20%3D%3D%3D%20%22iOS%22%29%7B%0A%09msg%20%3D%20%22Tap%20%E2%80%9DContinue%E2%80%9D%20and%20choose%20a%20text%20file%20from%20the%20forthcoming%20file%20picker%3A%22%0A%09var%20alert%20%3D%20new%20Alert%28%22Select%20File%22%2C%20msg%29%0A%09alert%2EaddOption%28%22Continue%22%29%0A%09alert%2Eshow%28function%28result%29%7B%0A%09%09pickerPromise%20%3D%20picker%2Eshow%28%29%0A%09%7D%29%0A%7D%20else%20if%20%28app%2EplatformName%20%3D%3D%3D%20%22macOS%22%29%7B%0A%09picker%2Emessage%20%3D%20%22Choose%20the%20text%20file%20to%20import%3A%22%0A%09pickerPromise%20%3D%20picker%2Eshow%28%29%0A%7D%0A%2F%2F%20READ%20CONTENTS%20OF%20THE%20CHOSEN%20TEXT%20FILE%0ApickerPromise%2Ethen%28function%28urls%29%7B%0A%09url%20%3D%20urls%5B0%5D%0A%09url%2Efetch%28function%28data%29%7B%0A%09%09console%2Elog%28data%2EtoString%28%29%29%0A%09%7D%29%0A%7D%29%7Dcatch%28err%29%7Bconsole%2Elog%28err%29%7D
Prompting the User
    

// CREATE INSTANCE OF FILEPICKER var picker = new FilePicker() picker.folders = false picker.multiple = false picker.types = [FileType.plainText] // DECLARE THE PROMISE VARIABLE var pickerPromise // CHECK PLATFORM if(app.platformName === "iOS"){ msg = "Tap ”Continue” and choose a text file from the forthcoming file picker:" var alert = new Alert("Select File", msg) alert.addOption("Continue") alert.show(function(result){ pickerPromise = picker.show() }) } else if (app.platformName === "macOS"){ picker.message = "Choose the text file to import:" pickerPromise = picker.show() } // READ CONTENTS OF THE CHOSEN TEXT FILE pickerPromise.then(function(urls){ url = urls[0] url.fetch(function(data){ console.log(data.toString()) }) })
ios-filepicker-prompt

JavaScript Promises and the FilePicker

A JavaScript Promise is standard built-in object of the JavaScript language. The JavaScript Promise object represents the eventual completion (or failure) of an asynchronous operation, and its resulting value.

The use of JavaScript Promises with Omni Automation, and the FilePicker class in particular, enables a simpler design for your scripts and actions that are meant to respond to events, such as the presentation and completion of a file picker dialog.

Instead of writing complex functions containing multiple call-backs, using JavaScript promises, scripts can divided into functions that are individually called when file picker dialogs have been either approved or dismissed.

Promises are generated when a file picker is displayed using the show(…) method of the FilePicker class. The resulting promise is stored in a variable so that its functions for responding to the dialog approval or cancelation can be identified and isolated in the script.

Run the following example script and view the scripting console after closing the file picker dialog to see the results of the promise.

Basic FilePicker Promise


// FILEPICKER INSTANCE CREATED AND PROPERTIES SET var picker = new FilePicker() picker.folders = false picker.multiple = false picker.types = [FileType.plainText] // PICKER PROMISE IS CREATED AND STORED WHEN PICKER IS DISPLAYED pickerPromise = picker.show() // PROMISE FUNCTION CALLED UPON PICKER APPROVAL pickerPromise.then(urlsArray => { aURL = urlsArray[0] // processing statements using url(s) console.log(aURL) }) // PROMISE FUNCTION CALLED UPON PICKER CANCELLATION pickerPromise.catch(err => { console.log("form cancelled", err.message) })

 02  Create a new empty file picker object and store it in a variable.

 03-05  Set the properties of the new file picker.

 08  Use the show(…) method of the FilePicker class to display the file picker dialog to the user. The result of this method is a new JavaScript Promise object that is stored in a variable.

 11-15  The then(…) method of the Promise class is used to process the promise upon approval of the file picker dialog. An array of URLs for the chosen items is passed into the method’s call-back function.

 18-20  A function that is called if the file picker dialog is cancelled.

Inline Promise Processing

As shown in the example above, the result of using the show(…) method to display a file picker dialog is a JavaScript promise object, which can then be processed using the then(…) or catch(…) functions depending on whether the dialog was approved or canceled.

If processing a canceled picker is not necessary for your script, you can streamline the script coding by appending the then(…) function to the show(…) function as shown in the example below. Functionally, this technique is the same as processing a promise object stored in a variable. The callback function within the then(…) function still receives the array of URLs chosen by the user in the file picker dialog.

Pick and Process


var picker = new FilePicker() picker.folders = false picker.multiple = false picker.types = [FileType.plainText] picker.show().then(function(urlsArray){ aURL = urlsArray[0] aURL.fetch(function(data){ console.log(data.toString()) }) })

 01  Create a new empty file picker object and store it in a variable.

 02-04  Set the properties of the new file picker.

 05  Use the show(…) method of the FilePicker class to display the file picker dialog to the user. The result of this method is a new JavaScript Promise object that is then processed by the appended then(…) function.

 06  A URL object is extracted from the URLs array passed by the promise as input to the call-back function.

 07-09  The fetch(…) method of the URL class is used to read the file represented by the extracted URL.

Promise Documentation

JavaScript Promises offer a high degree of customization beyond the basic use with forms shown here. Detailed information regarding JavaScript Promises is available at:

Using URL.FetchRequest to Read Chosen File

The example uses await statements within an asynchronous wrapper rather than explicit Promise blocks for implementing the file picker and the retrieval of file data.

The script uses the fetch() function with the URL.FetchRequest class to asynchronously read the contents of a file, rather than using the fetch() function of the URL class:

Read Contents of Text File


(async () => { try { picker = new FilePicker() picker.folders = false picker.multiple = false picker.types = [FileType.plainText] urls = await picker.show() fileRequest = new URL.FetchRequest() fileRequest.url = urls[0] fileContents = await fileRequest.fetch().then(file => file.bodyString) Pasteboard.general.string = fileContents } catch(err){ if(!err.causedByUserCancelling){ new Alert(err.name, err.message).show() } } })();