Document Export
OmniOutliner supports the export of outlines to documents of various formats, such as to standard office, spreadsheet, text, and HTML formats.
This section examines how to create instances of the FileWrapper class in preparation for the export of documents and content.
Documentation regarding the other classes involved in the saving and export of OmniPlan documents can be found in FileTypes and FileSavers.
FileWrappers
If you think of an outline as a set of data, then it’s easy to understand that an outline’s data can be packaged in a variety of ways. Each “data package” has a set of parameters that determine how the outline data is stored or presented.
For example, one package may store the data as tabbed data, while another may store the outline data in XML format. Each of the supported file packaging formats has its own set of parameters. In terms of Omni Automation, these file packages are referred to as FileWrappers.
Each instance of the FileWrapper class has a unique type identifier that identifies that wrapper. To get a list of the export types supported by OmniOutliner, write a simple script to access the value of the writableTypes property of the Document class. The result will be an array of the identifiers for the FileWrappers supported in OmniOutliner.
NOTE: a complete list of all readable and writeable filetypes supported by OmniOutliner is available here.
Writable Types | ||
01 | document.writableTypes | |
02 | //--> ["com.omnigroup.omnioutliner.xmlooutline", | |
03 | // To return as a text block: | |
04 | document.writableTypes.join('\n') |
A writable type is used when creating a new FileWrapper instance by using the makeFileWrapper(…) function of the Document class:
Create File Wrapper Instance | ||
01 | fileTypeID = "com.omnigroup.OmniOutliner.CSVExport.CSV" | |
02 | baseName = document.name | |
03 | wrapperPromise = document.makeFileWrapper(baseName, fileTypeID) | |
04 | ||
05 | wrapperPromise.then(function(wrapper){ | |
06 | console.log(wrapper) | |
07 | //--> [object FileWrapper: file, 2729 bytes] | |
08 | }) | |
09 | ||
10 | wrapperPromise.catch(function(err){ | |
11 | console.error(err.message) | |
12 | }) |
01 The file type identifier for the desired export format.
02 The name that should be used for the exported document. Note that if a file saver dialog is used in the export script, the user may change the provided file name. Also note that if the export format is HTML, the provided name will be used to name the folder containing the main HTML file and supporting files.
03 The makeFileWrapper(…) function of the Document class is used to create a file wrapper instance. Since it make take some time to complete the creation of a complex file wrapper, the result of this command is a JavaScript promise object, whose resulting content will be processed elsewhere in the export script. The file name and file type ID (optional) are provided as function parameters. Note that if the optional type ID is not provided, the default file format is used automatically.
05-08 The then(…) method of the Promise class is used to process the contents of the JavaScript promise created earlier in the script. The file wrapper generated by the previous makeFileWrapper(…) function is passed into this function so that it may processed by those statements placed within the function.
10-12 The catch(…) method of the Promise class is called in the event that there is a problem with the creation of the file wrapper.
Instance Properties
Each FileWrapper instance has a set of supported properties, most of which have values that are read-only, with the exception of the preferredFilename property whose value can be set in a script.
children (Array of FileWrapper r/o) • Returns an Array of child FileWrappers, if this represents a directory. Otherwise, an empty array is returned.
contents (String or nil r/o Data) • Returns the regular file contents of the wrapper, if this represents a regular file. Otherwise, null is returned.
destination (URL or nil r/o) • Returns the destination if this represents a symbolic link. Otherwise, null is returned.
filename (String or nil) • Returns the actual file name that was last read for this file wrapper. Depending on the names of other sibling wrappers, this may not be what file name will be written.
preferredFilename (String or nil) • Returns the preferred file name that should be used when writing the file wrapper if no other file in the same parent directory wrapper is in use.
type (FileWrapper.Type r/o) • Returns the type of this FileWrapper
The value of the contents property is a representation of the outline data, which can be manipulated using class and instance functions from the Data class, such as the toBase64() function shown in the following example:
Base 64 Encode New File Wrapper Instance | ||
01 | fileTypeID = "com.omnigroup.OmniOutliner.CSVExport.CSV" | |
02 | baseName = document.name | |
03 | wrapperPromise = document.makeFileWrapper(baseName, fileTypeID) | |
04 | ||
05 | wrapperPromise.then(function(wrapper){ | |
06 | console.log(wrapper) | |
07 | encodedData = wrapper.contents.toBase64() | |
08 | }) | |
09 | ||
10 | wrapperPromise.catch(function(err){ | |
11 | console.error(err.message) | |
12 | }) |
Class Functions
The class functions for the FileWrapper class:
withContents(name:String or nil, contents:Data or nil) → (FileWrapper) • Returns a new FileWrapper instance that represents a flat file containing the given data.
New Wrapper with Text Data | ||
01 | fileName = "Cow.txt" | |
02 | textData = Data.fromString("How now brown cow") | |
03 | wrapper = FileWrapper.withContents(fileName, textData) |
It may be desired to perform multiple exports of a document to files in a variety of formats. The withChildren(…) class function can be used to create a folder containing one or more exported documents.
withChildren(name:String or nil, contents:Data or nil) → (FileWrapper) • Returns a new FileWrapper instance that represents a directory with the given child file wrappers. Each child file wrapper must have a unique name specified.
Multiple Exports | ||
01 | docName = document.name | |
02 | ||
03 | var fileTypeID1 = "org.opml.opml" | |
04 | var fileTypeID2 = "com.omnigroup.OmniOutliner.CSVExport.CSV" | |
05 | wrapperPromise1 = document.makeFileWrapper(docName + ".opml", fileTypeID1) | |
06 | wrapperPromise2 = document.makeFileWrapper(docName + ".csv", fileTypeID2) | |
07 | promises = [wrapperPromise1,wrapperPromise2] | |
08 | ||
09 | Promise.all(promises).then(function(fileWrappers){ | |
10 | ||
11 | filesaver = new FileSaver() | |
12 | folderType = new FileType("public.folder") | |
13 | fileType1 = new FileType(fileTypeID1) | |
14 | fileType2 = new FileType(fileTypeID2) | |
15 | filesaver.types = [folderType, fileType1, fileType2] | |
16 | fldrwrapper = FileWrapper.withChildren("Export Folder",fileWrappers) | |
17 | fileSaverPromise = filesaver.show(fldrwrapper) | |
18 | ||
19 | fileSaverPromise.then(function(urlObj){ | |
20 | console.log(urlObj.string) // file url to directory | |
21 | }) | |
22 | ||
23 | fileSaverPromise.catch(function(err){ | |
24 | console.log(err.message) | |
25 | }) | |
26 | ||
27 | }).catch(function(err){ | |
28 | console.log("Error", err.message) | |
29 | }) |
01 Get the name of the current OmniOutliner document.
03-04 The file type identifiers for the desired exports, in this example they are: OPML (Outline Processor Markup Language), and CSV (Comma-Separated Values)
05 The makeFileWrapper(…) function of the Document class is used to generate the first file wrapper, by using the document name appending with the appropriate export file extension, and the corresponding file type ID. The result is a JavaScript promise object.
06 The makeFileWrapper(…) function of the Document class is used to generate the second file wrapper, by using the document name appending with the appropriate export file extension, and the corresponding file type ID. The result is a JavaScript promise object.
07 An array of the generated JavaScript promise objects is stored in the variable: promises
09-27 The all(…) method of the Promise class is completed when all of the promises passed into the function are ready for processing. The then(…) function is appended to all(…) function in order to process the passed promises.
11 This example script incorporates the use of a file saver dialog to allow the user to choose the name and location for the folder that will contain the exported documents. A new instance of the FileSaver class is created and stored in the variable: filesaver
12 Generate a file type object for a folder.
13-14 Generate file type objects for the desired export file type IDs.
15 Set the file types of the file saver object to the array of generated file types. Note that the array should always begin with the folder type object.
16 The withChildren(…) function of the FileWrapper class generates a file wrapper object for the export folder by passing in the folder name and array of export file wrappers as the function’s parameters.
17 The show(…) method is used to display the file saver dialog, and the result of the method is a JavaScript promise object that will eventually contain the URL to the exported folder.
19-21 The then(…) function of the Promise class is automatically called after the user has completed the file saver dialog, with a URL object reference to the export folder being passed into the function.
23-25 The catch(…) function of the Promise class is called if the file saver dialog is canceled.
Instance Functions
The instance functions for the FileWrapper class:
filenameForChild(child:FileWrapper) → (String or nil) • Returns the unique file name that will be used for the given child FileWrapper, or null if this file wrapper is not a child of the receiver.
FileWrapper.Type
The class properties of a FileWrapper.Type:
Directory --> (FileWrapper.Type r/o) • A FileWrapper that represents a directory with zero or more child wrappers.
File --> (FileWrapper.Type r/o) • A FileWrapper that represents a regular file with data contents.
Link --> (FileWrapper.Type r/o) • A FileWrapper that represents a symbolic link to another location.
As mentioned previously, here is a full explanation of the FileWrapper.Types supported by OmniOutliner:
FileWrappers Types | ||
01 | document.writableTypes.join('\n') | |
02 | //-> FileWrapper Types as paragraphs |
Here are the various export formats with their corresponding FileWrapper.Type:
Export Examples
Here are some examples of using FileWrappers to export OmniOutliner documents.
Here’s an Omni Automation script for creating a new task in OmniFocus with the current OmniOutliner document as an attachment. The script uses the integrated URL support in OmniFocus to create and run a URL link for creating tasks:
New OmniFocus Task with Document Attachment | ||
01 | wrapperPromise = document.makeFileWrapper(document.name) | |
02 | ||
03 | wrapperPromise.then(function(wrapper){ | |
04 | taskName = encodeURIComponent(document.name) | |
05 | attachmentName = encodeURIComponent(wrapper.preferredFilename) | |
06 | encodedData = wrapper.contents.toBase64() | |
07 | urlStr = "omnifocus://localhost/add?name=" + taskName + "&attachment=" + encodedData + "&attachment-name=" + attachmentName | |
08 | URL.fromString(urlStr).open() | |
09 | }) | |
10 | ||
11 | wrapperPromise.catch(function(err){ | |
12 | console.error(err.message) | |
13 | }) |
1 Use the makeFileWrapper(…) function of the Document class to generate a file wrapper, passing-in the name of the document to be used as the name of the export file. Since no export file type has been specified as a second parameter, the default export file format will be used. The result of the function is an instance of a JavaScript promise.
03-09 The then(…) function of the Promise class is used to process the file wrapper once it has been created, and is passed into the function.
04 Encode the document name to be used as the name of the task.
05 Encode the document file name to be used as the attachment name.
06 Encode the contents of the document in Base64 encoding format, which results in a string of URL approved characters.
07 Combine the encoded elements into the URL format supported by OmniFocus.
08 Convert the URL string into a URL object and execute it using the call() method.
More information about implementing the previous script as an Omni Automation action can be found here.
The following example script utilize the built-in eMail support in OmniOutliner to add export copies of the current document to new outgoing mail messages:
Send Plain-Text Version of Document | ||
01 | fileTypeID = "public.plain-text" | |
02 | baseName = document.name | |
03 | wrapperPromise = document.makeFileWrapper(baseName, fileTypeID) | |
04 | ||
05 | wrapperPromise.then(function(wrapper){ | |
07 | var email = new Email() | |
08 | email.subject = "Plain-Text Version of “" + document.name + "”" | |
09 | email.body = "Here is the plain-text version of the document for you!\n\n" | |
10 | email.fileWrappers = [wrapper] | |
11 | email.generate() | |
12 | }) | |
13 | ||
14 | wrapperPromise.catch(function(err){ | |
15 | console.error(err.message) | |
16 | }) |
You can use the contents property of the FileWrapper class to generate text content for an outgoing email message.
Send Outline Contents | ||
01 | fileTypeID = "public.plain-text" | |
02 | baseName = document.name | |
03 | wrapperPromise = document.makeFileWrapper(baseName, fileTypeID) | |
04 | ||
05 | wrapperPromise.then(function(wrapper){ | |
06 | outlineText = wrapper.contents.toString() | |
07 | var email = new Email() | |
08 | email.subject = "Plain-Text Version of “" + document.name + "”" | |
09 | email.body = outlineText | |
10 | email.generate() | |
11 | }) | |
12 | ||
13 | wrapperPromise.catch(function(err){ | |
14 | console.error(err.message) | |
15 | } |
Here’s an action that uses the same export technique to send the current outline to the Drafts application as plain text:
Send Outline to Drafts in Plain-Text Format | ||
01 | /*{ | |
02 | "type": "action", | |
03 | "targets": ["omnioutliner"], | |
04 | "author": "Otto Automator", | |
05 | "identifier": "com.omni-automation.oo.export-outline-to-drafts-as-plain-text", | |
06 | "version": "1.0", | |
07 | "description": "This action will create a new document in the Drafts app with the contents of the outline in plain text format.", | |
08 | "label": "Drafts • Export to Drafts as Plain Text Outline", | |
09 | "shortLabel": "Export to Drafts" | |
10 | }*/ | |
11 | (() => { | |
12 | var action = new PlugIn.Action(function(selection, sender){ | |
13 | // action code | |
14 | ||
15 | // "com.apple.news.opml" "org.opml.opml" "public.plain-text" | |
16 | var fileTypeID = "public.plain-text" | |
17 | var baseName = "Outline" | |
18 | var wrapperPromise = document.makeFileWrapper(baseName, fileTypeID) | |
19 | ||
20 | wrapperPromise.then(function(wrapper){ | |
21 | var outlineText = wrapper.contents.toString() | |
22 | var encodedStr = encodeURIComponent(outlineText) | |
23 | var urlStr = "drafts5://x-callback-url/create?text=" + encodedStr | |
24 | var url = URL.fromString(urlStr) | |
25 | url.call(function(result){console.log(result)}) | |
26 | }) | |
27 | ||
28 | wrapperPromise.catch(function(err){ | |
29 | console.error(err.message) | |
30 | }) | |
31 | }); | |
32 | ||
33 | action.validate = function(selection, sender){ | |
34 | // validation code | |
35 | return (rootItem.descendants.length > 0) | |
36 | }; | |
37 | ||
38 | return action; | |
39 | })(); |
Export to HTML
The following Omni Automation plug-in will export the current outline to disk as a folder containing an HTML file with supporting files.
This plug-in uses an action form to prompt the user to select the export parameters to use. In addition, the action displays a file saver dialog from which the user determines the name and location to be used for the exported HTML folder.
The action code incorporates three uses of the JavaScript Promise class: 1) for form creation and display; 2) for generating the export file wrapper; and 3) for displaying and responding to the file saver dialog.
Export to HTML | ||
01 | /*{ | |
02 | "type": "action", | |
03 | "targets": ["omnioutliner"], | |
04 | "author": "Otto Automator", | |
05 | "identifier": "com.omni-automation.oo-export-to-html", | |
06 | "version": "1.0", | |
07 | "description": "This action will export the current outline in either simple or dynamic HTML format.", | |
08 | "label": "Export to HTML", | |
09 | "shortLabel": "Export to HTML" | |
10 | }*/ | |
11 | (() => { | |
12 | var action = new PlugIn.Action(function(selection, sender){ | |
13 | // action code | |
14 | // selection options: columns, document, editor, items, nodes, outline, styles | |
15 | ||
16 | var paramtersForm = new Form() | |
17 | ||
18 | dynamicCheckbox = new Form.Field.Checkbox( | |
19 | "dynamicCheckbox", | |
20 | "Enable dynamic controls (disclosure triangles, checkboxes, etc.)", | |
21 | false | |
22 | ) | |
23 | ||
24 | openFileCheckbox = new Form.Field.Checkbox( | |
25 | "openFileCheckbox", | |
26 | "Display HTML after export", | |
27 | false | |
28 | ) | |
29 | ||
30 | paramtersForm.addField(dynamicCheckbox) | |
31 | paramtersForm.addField(openFileCheckbox) | |
32 | ||
33 | formPromise = paramtersForm.show("HTML Export:","Continue") | |
34 | ||
35 | formPromise.then(function(formObject){ | |
36 | var shouldExportAsDynamic = formObject.values['dynamicCheckbox'] | |
37 | if(shouldExportAsDynamic){ | |
38 | fileTypeID = "com.omnigroup.OmniOutliner.HTMLExport.HTMLDynamic" | |
39 | } else { | |
40 | fileTypeID = "com.omnigroup.OmniOutliner.SimpleHTMLExport.HTML" | |
41 | } | |
42 | var shouldDisplayAfterExport = formObject.values['openFileCheckbox'] | |
43 | ||
44 | var baseName = document.name | |
45 | wrapperPromise = document.makeFileWrapper(baseName, fileTypeID) | |
46 | ||
47 | wrapperPromise.then(function(wrapper){ | |
48 | filesaver = new FileSaver() | |
49 | fileSaverPromise = filesaver.show(wrapper) | |
50 | ||
51 | fileSaverPromise.then(function(urlObj){ | |
52 | console.log(urlObj.string) | |
53 | if(shouldDisplayAfterExport){ | |
54 | urlStr = urlObj.string + "/index.html" | |
55 | URL.fromString(urlStr).open() | |
56 | } | |
57 | }) | |
58 | ||
59 | fileSaverPromise.catch(function(err){ | |
60 | console.log(err.message) | |
61 | }) | |
62 | }).catch(function(err){console.log(err.message)}) | |
63 | }) | |
64 | }); | |
65 | ||
66 | action.validate = function(selection, sender){ | |
67 | // validation code | |
68 | // selection options: columns, document, editor, items, nodes, outline, styles | |
69 | return true | |
70 | }; | |
71 | ||
72 | return action; | |
73 | })(); |
This webpage is in the process of being developed. Any content may change and may not be accurate or complete at this time.