One of the powerful features of OmniJS is the ability to share data between applications by using a Call and Response technique where data is retrieved from a second application to be used by the host application.
In a Call and Response scenario, a script targeting the host application is executed. This script uses the tellScript() method of the URL class to generate an OmniJS url containing a function for extracting data from a second application. The main script then uses the call() method of the URL class to send the URL, causing the passed function to be executed by the targeted application, which returns the function result to the main script. The main script then uses the returned data in manipulating the host application.
The short video below demonstrates the concept of Call and Response:
Retrieving Data
The example function (shown below) is designed to extract the properties of every item of the current OmniOutliner outline, and return them as an array of individual JavaScript objects.
function outlineToObjectsArray(){
var array = new Array()
items = rootItem.descendants
for(i = 0; i < items.length; i++){
item = items[i]
obj = new Object()
obj.level = item.level
obj.index = item.index
obj.topic = item.topic
array.push(obj)
}
return array
}
The function uses the OmniOutliner descendants property of the rootItem class to generate an ordered list of every item of the outline. This list is then iterated in order to create an array of JavaScript objects, each of which contains the values of the level, index, and topic properties of the outline item.
The result of function is an array similar in structure to this:
To convert the resulting array of JavaScript objects into a data format suitable for passing from the function to the main script, the returning line of the function (line 12) is changed so that the array is converted into a string by using the stringify() method of the JSON class, and then the resulting string is encoded using the standard JavaScript encodeURIComponent() method. The encoded function result will be decoded in the main script (below: line 23).
Outline to JSON String
12
returnencodeURIComponent(JSON.stringify(array))
Retrieve and Build
Here’s a script that uses Call and Response to create a set of slides in OmniGraffle based upon the contents of the current OmniOutliner document.
var alert = new Alert("Confirmation", "This script will import the topics from the current OmniOutliner document to OmniGraffle as canvas slides.\n\nShould the script continue?")
alert.addOption("Continue")
alert.addOption("Stop")
alert.show(function(result){
if (result == 1){
throw new Error('script cancelled')
} else {
function outlineToObjectsArray(){
var array = new Array()
items = rootItem.descendants
for(i = 0; i < items.length; i++){
item = items[i]
obj = new Object()
obj.level = item.level
obj.index = item.index
obj.topic = item.topic
array.push(obj)
}
return encodeURIComponent(JSON.stringify(array))
}
var scriptURL = URL.tellScript("omnioutliner", outlineToObjectsArray.toString() + '\n' + 'outlineToObjectsArray()')
scriptURL.call(function(reply){
reply = decodeURIComponent(reply)
reply = JSON.parse(reply)
// title and body size and position are based upon current canvas dimensions
var cnvs = document.windows[0].selection.canvas
var cnvsSize = cnvs.size
var cW = cnvsSize.width
var cH = cnvsSize.height
var vM = Math.round(cH/12)
var hM = Math.round(cW/12)
var boxOffset = Math.round(cH/32)
var titleSize = Math.round(cW/14)
var bodySize = Math.round(cW/20)
var lineHeightPercentage = 1.25
var titleBoxRect = new Rect(hM, vM, cW - hM*2, titleSize * lineHeightPercentage)
var bodyBoxRect = new Rect(hM, vM + titleBoxRect.height + boxOffset, cW - hM*2, cH - vM*2 - boxOffset - titleBoxRect.height)
// font family defaults
var titleFontPSName = 'HelveticaNeue-Medium'
var bodyFontPSName = 'HelveticaNeue'
for(i = 0; i < reply.length; i++){
// retrieve item data
obj = reply[i]
objIndex = obj.index
objLevel = obj.level
objTopic = obj.topic
// create new canvas for each top-level item
if (objLevel == 1){
cnvs = addCanvas()
cnvs.size = cnvsSize
cnvs.canvasSizingMode = CanvasSizingMode.Fixed
// create a slide title box
shape = cnvs.addShape('Rectangle',titleBoxRect)
shape.name = 'Slide Title'
shape.textHorizontalPadding = 0
shape.textVerticalPadding = 0
shape.text = objTopic
shape.fontName = titleFontPSName
shape.autosizing = TextAutosizing.Overflow
shape.textHorizontalAlignment = HorizontalTextAlignment.Left
shape.textVerticalPlacement = VerticalTextPlacement.Middle
shape.textSize = titleSize
shape.fillColor = null
shape.shadowColor = null
shape.strokeColor = null
// create a slide body box
shape = cnvs.addShape('Rectangle',bodyBoxRect)
shape.name = 'Slide Body'
shape.textHorizontalPadding = 0
shape.textVerticalPadding = 0
shape.text = ' '
shape.fontName = bodyFontPSName
shape.autosizing = TextAutosizing.Overflow
shape.textHorizontalAlignment = HorizontalTextAlignment.Left
shape.textVerticalPlacement = VerticalTextPlacement.Top
shape.textSize = bodySize
shape.fillColor = null
shape.shadowColor = null
shape.strokeColor = null
} else if (objLevel == 2){
bodyShape = cnvs.graphicWithName('Slide Body')
bodyText = bodyShape.text
if (bodyText == '' || bodyText == ' '){
bodyShape.text = '•' + ' ' + objTopic
} else {
bodyShape.text = bodyText + '\n' + '•' + ' ' + objTopic
}
bodyShape.textSize = bodySize
}
}
})
}
})
varalert = newAlert("Confirmation", "This script will import the topics from the current OmniOutliner document to OmniGraffle as canvas slides.\n\nShould the script continue?")
Here’s a short video demonstrating App-to-App scripting between OmniGraffle and OmniOutliner (macOS). In the shown example, the topics from an OmniOutliner document are used to create slides in the current OmniGraffle document.
TIP: the video shows the use of OmniJS scripts implemented as actions for the “Presentation Tools” OmniGraffle plugin. TAP|CLICK to download the plugin.
UNDER CONSTRUCTION
This webpage is in the process of being developed. Any content may change and may not be accurate or complete at this time.