Outline Example

The following script example incorporates the properties and methods of the Outline, Item, and Editor classes to automate the manipulation of an OmniOutliner document based upon JSON (JavaScript Object Notation) data imported from a server.

Import, Parse, and Build

The provided script example is functionally comprised of two sections:

[ { "name": "Georgette Vega", "company": "GOGOL", "email": "georgettevega@gogol.com", "phone": "(823) 413-2747", "member": true, "date": "2016-02-02T07:14:41 +08:00" }, { "name": "Beatrice Cortez", "company": "XYQAG", "email": "beatricecortez@xyqag.com", "phone": "(889) 579-3514", "member": false, "date": "2016-11-30T01:45:07 +08:00" }, { "name": "Bernadette Hunter", "company": "ISOLOGICA", "email": "bernadettehunter@isologica.com", "phone": "(876) 452-3767", "member": false, "date": "2017-08-03T06:33:23 +07:00" }, { "name": "Jodie Rasmussen", "company": "INSURETY", "email": "jodierasmussen@insurety.com", "phone": "(937) 538-3980", "member": true, "date": "2018-06-19T06:07:16 +07:00" }, { "name": "Ramsey Irwin", "company": "OLYMPIX", "email": "ramseyirwin@olympix.com", "phone": "(983) 562-3120", "member": true, "date": "2015-04-20T10:15:54 +07:00" }, { "name": "Cochran Wiley", "company": "MICRONAUT", "email": "cochranwiley@micronaut.com", "phone": "(914) 544-3692", "member": false, "date": "2018-03-26T12:03:59 +07:00" } ]

As shown in the data snapshot above, each example JSON object contains five data pairs. These pairs are represented in the OmniOutliner document as columns, and each data object in the imported data object becomes a row in the outline.

NOTE: If an object pair has a value that is a string, the value is checked to see if it is a date string and if true, a date column is added instead of text column.

Import JSON from URL Action

The following Omni Automation action presents an action form displaying a text field in which you may enter the http or https URL to the source JSON server or file. Optionally, select the checkbox if you want to use the example JSON content from a file hosted on this website.

import-json-url-form
urlStr = 'https://omni-automation.com/omnioutliner/people.json' var url = URL.fromString(urlStr) url.fetch(function(data){ objArray = JSON.parse(data.toString()) // add columns based upon contents of 1st object var obj1 = objArray[0] var objectKeys = Object.keys(obj1) var tree = document.outline var editor = document.editors[0] // add columns as necessary var addedColumns = new Array() objectKeys.forEach(key => { var dataType = typeof obj1[key] switch(dataType){ case "string": // check for date string var strToCheck = obj1[key] var str = strToCheck.replace(/\s/g, '') var result = Date.parse(str) if(result > 0){ console.log("Add date column") var newColumn = tree.addColumn( Column.Type.Date, editor.afterColumn(), function(column){ column.title = key column.formatter = Formatter.Date.withStyle(Formatter.Date.Style.Short) } ) } else { console.log("Add text column") var newColumn = tree.addColumn( Column.Type.Text, editor.afterColumn(), function(column){ column.title = key } ) } addedColumns.push(newColumn) break case "number": console.log("Add number column") var newColumn = tree.addColumn( Column.Type.Number, editor.afterColumn(), function(column){ column.title = key column.formatter = Formatter.Decimal.plain } ) addedColumns.push(newColumn) break case "boolean": console.log("Add checkbox column") var newColumn = tree.addColumn( Column.Type.Checkbox, editor.afterColumn(), function(column){ column.title = key column.style.set(Style.Attribute.ParagraphAlignment, TextAlignment.Center) } ) addedColumns.push(newColumn) } }) // Populate the data objArray.forEach(obj =>{ var newRow = rootItem.addChild() objectKeys.forEach(function(key,index,array){ var cellValue = obj[key] if (typeof cellValue === "boolean"){ cellValue = (cellValue === true)? State.Checked:State.Unchecked } else if (addedColumns[index].type === Column.Type.Date){ cellValue = cellValue.replace(/\s/g, '') cellValue = new Date(cellValue) } newRow.setValueForColumn(cellValue,addedColumns[index]) }) }) })
/*{ "type": "action", "targets": ["omnioutliner"], "author": "Otto Automator", "identifier": "com.omni-automation.oo.json-import-from-url", "version": "1.0", "description": "This action will import the JSON data from the provided http or https URL, parse the data, and add the columns and rows necessary to express the data.", "label": "Import JSON from URL", "shortLabel": "JSON Import" }*/ (() => { var action = new PlugIn.Action(function(selection, sender){ // action code // selection options: columns, document, editor, items, nodes, outline, styles // CREATE FORM FOR GATHERING USER INPUT var inputForm = new Form() // CREATE TEXT FIELD var textField = new Form.Field.String( "textInput", null, null ) // CREATE CHECKBOX var checkSwitchField = new Form.Field.Checkbox( "checkboxSwitch", "Import JSON from demo file", false ) // ADD THE FIELDS TO THE FORM inputForm.addField(textField) inputForm.addField(checkSwitchField) // PRESENT THE FORM TO THE USER formPrompt = "Enter the URL to the JSON data server or file:" formPromise = inputForm.show(formPrompt,"Continue") // VALIDATE THE USER INPUT inputForm.validate = function(formObject){ var checkboxValue = formObject.values["checkboxSwitch"] if (checkboxValue){return true} var textValue = formObject.values["textInput"] var textStatus = (textValue && textValue.length > 0) ? true:false if (textStatus){ return (textValue.startsWith("http://", 0) || textValue.startsWith("https://", 0) && textValue.length > 10) ? true : false } return false } // PROCESSING USING THE DATA EXTRACTED FROM THE FORM formPromise.then(function(formObject){ var checkboxValue = formObject.values["checkboxSwitch"] if(checkboxValue){ var urlStr = "https://omni-automation.com/omnioutliner/people.json" } else { var urlStr = formObject.values["textInput"] } var url = URL.fromString(urlStr) url.fetch(function(data){ objArray = JSON.parse(data.toString()) // add columns based upon contents of 1st object var obj1 = objArray[0] var objectKeys = Object.keys(obj1) var tree = document.outline var editor = document.editors[0] // add columns as necessary var addedColumns = new Array() objectKeys.forEach(key => { var dataType = typeof obj1[key] switch(dataType){ case "string": // check for date string var strToCheck = obj1[key] var str = strToCheck.replace(/\s/g, '') var result = Date.parse(str) if(result > 0){ console.log("Add date column") var newColumn = tree.addColumn( Column.Type.Date, editor.afterColumn(), function(column){ column.title = key column.formatter = Formatter.Date.withStyle(Formatter.Date.Style.Short) } ) } else { console.log("Add text column") var newColumn = tree.addColumn( Column.Type.Text, editor.afterColumn(), function(column){ column.title = key } ) } addedColumns.push(newColumn) break case "number": console.log("Add number column") var newColumn = tree.addColumn( Column.Type.Number, editor.afterColumn(), function(column){ column.title = key column.formatter = Formatter.Decimal.plain } ) addedColumns.push(newColumn) break case "boolean": console.log("Add checkbox column") var newColumn = tree.addColumn( Column.Type.Checkbox, editor.afterColumn(), function(column){ column.title = key column.style.set(Style.Attribute.ParagraphAlignment, TextAlignment.Center) } ) addedColumns.push(newColumn) } }) // Populate the data objArray.forEach(obj =>{ var newRow = rootItem.addChild() objectKeys.forEach(function(key,index,array){ var cellValue = obj[key] if (typeof cellValue === "boolean"){ cellValue = (cellValue === true)? State.Checked:State.Unchecked } else if (addedColumns[index].type === Column.Type.Date){ cellValue = cellValue.replace(/\s/g, '') cellValue = new Date(cellValue) } newRow.setValueForColumn(cellValue,addedColumns[index]) }) }) }) }) // PROMISE FUNCTION CALLED UPON FORM CANCELLATION formPromise.catch(function(err){ console.log("form cancelled", err.message) }) }); action.validate = function(selection, sender){ // validation code // selection options: columns, document, editor, items, nodes, outline, styles return true }; return action; })();
omnioutliner://localhost/omnijs-run?script=try%7BurlStr%20%3D%20%27https%3A%2F%2Fomni%2Dautomation%2Ecom%2Fomnioutliner%2Fpeople%2Ejson%27%0Avar%20url%20%3D%20URL%2EfromString%28urlStr%29%0Aurl%2Efetch%28function%28data%29%7B%0A%09objArray%20%3D%20JSON%2Eparse%28data%2EtoString%28%29%29%0A%0A%09%2F%2F%20add%20columns%20based%20upon%20contents%20of%201st%20object%0A%09var%20obj1%20%3D%20objArray%5B0%5D%0A%09var%20objectKeys%20%3D%20Object%2Ekeys%28obj1%29%0A%09var%20tree%20%3D%20document%2Eoutline%0A%09var%20editor%20%3D%20document%2Eeditors%5B0%5D%0A%0A%09%2F%2F%20add%20columns%20as%20necessary%0A%09var%20addedColumns%20%3D%20new%20Array%28%29%0A%09objectKeys%2EforEach%28key%20%3D%3E%20%7B%0A%09%09var%20dataType%20%3D%20typeof%20obj1%5Bkey%5D%0A%09%09switch%28dataType%29%7B%0A%09%09%09case%20%22string%22%3A%0A%09%09%09%09%2F%2F%20check%20for%20date%20string%0A%09%09%09%09var%20strToCheck%20%3D%20obj1%5Bkey%5D%0A%09%09%09%09var%20str%20%3D%20strToCheck%2Ereplace%28%2F%5Cs%2Fg%2C%20%27%27%29%0A%09%09%09%09var%20result%20%3D%20Date%2Eparse%28str%29%0A%09%09%09%09if%28result%20%3E%200%29%7B%0A%09%09%09%09%09console%2Elog%28%22Add%20date%20column%22%29%0A%09%09%09%09%09var%20newColumn%20%3D%20tree%2EaddColumn%28%0A%09%09%09%09%09%09Column%2EType%2EDate%2C%0A%09%09%09%09%09%09editor%2EafterColumn%28%29%2C%20%0A%09%09%09%09%09%09function%28column%29%7B%0A%09%09%09%09%09%09%09column%2Etitle%20%3D%20key%0A%09%09%09%09%09%09%09column%2Eformatter%20%3D%20%09Formatter%2EDate%2EwithStyle%28Formatter%2EDate%2EStyle%2EShort%29%0A%09%09%09%09%09%09%7D%0A%09%09%09%09%09%29%09%09%09%09%09%09%09%0A%09%09%09%09%7D%20else%20%7B%0A%09%09%09%09%09console%2Elog%28%22Add%20text%20column%22%29%0A%09%09%09%09%09var%20newColumn%20%3D%20tree%2EaddColumn%28%0A%09%09%09%09%09%09Column%2EType%2EText%2C%0A%09%09%09%09%09%09editor%2EafterColumn%28%29%2C%20%0A%09%09%09%09%09%09function%28column%29%7B%0A%09%09%09%09%09%09%09column%2Etitle%20%3D%20key%0A%09%09%09%09%09%09%7D%0A%09%09%09%09%09%29%0A%09%09%09%09%7D%0A%09%09%09%09addedColumns%2Epush%28newColumn%29%0A%09%09%09%09break%0A%09%09%09case%20%22number%22%3A%0A%09%09%09%09console%2Elog%28%22Add%20number%20column%22%29%0A%09%09%09%09var%20newColumn%20%3D%20tree%2EaddColumn%28%0A%09%09%09%09%09Column%2EType%2ENumber%2C%0A%09%09%09%09%09editor%2EafterColumn%28%29%2C%20%0A%09%09%09%09%09function%28column%29%7B%0A%09%09%09%09%09%09column%2Etitle%20%3D%20key%0A%09%09%09%09%09%09column%2Eformatter%20%3D%20Formatter%2EDecimal%2Eplain%0A%09%09%09%09%09%7D%0A%09%09%09%09%29%0A%09%09%09%09addedColumns%2Epush%28newColumn%29%0A%09%09%09%09break%0A%09%09%09case%20%22boolean%22%3A%0A%09%09%09%09console%2Elog%28%22Add%20checkbox%20column%22%29%0A%09%09%09%09var%20newColumn%20%3D%20tree%2EaddColumn%28%0A%09%09%09%09%09Column%2EType%2ECheckbox%2C%0A%09%09%09%09%09editor%2EafterColumn%28%29%2C%20%0A%09%09%09%09%09function%28column%29%7B%0A%09%09%09%09%09%09column%2Etitle%20%3D%20key%0A%09%09%09%09%09%09column%2Estyle%2Eset%28Style%2EAttribute%2EParagraphAlignment%2C%20TextAlignment%2ECenter%29%0A%09%09%09%09%09%7D%0A%09%09%09%09%29%0A%09%09%09%09addedColumns%2Epush%28newColumn%29%0A%09%09%7D%09%09%0A%09%7D%29%0A%0A%09%2F%2F%20Populate%20the%20data%0A%09objArray%2EforEach%28obj%20%3D%3E%7B%0A%09%09var%20newRow%20%3D%20rootItem%2EaddChild%28%29%0A%09%09objectKeys%2EforEach%28function%28key%2Cindex%2Carray%29%7B%0A%09%09%09var%20cellValue%20%3D%20obj%5Bkey%5D%0A%09%09%09if%20%28typeof%20cellValue%20%3D%3D%3D%20%22boolean%22%29%7B%0A%09%09%09%09cellValue%20%3D%20%28cellValue%20%3D%3D%3D%20true%29%3F%20State%2EChecked%3AState%2EUnchecked%0A%09%09%09%7D%20else%20if%20%28addedColumns%5Bindex%5D%2Etype%20%3D%3D%3D%20Column%2EType%2EDate%29%7B%0A%09%09%09%09cellValue%20%3D%20cellValue%2Ereplace%28%2F%5Cs%2Fg%2C%20%27%27%29%0A%09%09%09%09cellValue%20%3D%20new%20Date%28cellValue%29%0A%09%09%09%7D%0A%09%09%09newRow%2EsetValueForColumn%28cellValue%2CaddedColumns%5Bindex%5D%29%0A%09%09%7D%29%0A%09%7D%29%0A%7D%29%7Dcatch%28err%29%7Bconsole%2Elog%28err%29%7D
doc-from-json

Merge Selected Text Column into Topic Column

In the previous script, new columns are created for each data pair of the imported JSON, leaving the document’s default Topic column untouched. The following script enables you to select one of the created text columns and merge its content into the default Topic column, either replacing existing content or appending to it. After merging, the selected column will be removed from the outline.

merge-form
/*{ "type": "action", "targets": ["omnioutliner"], "author": "Otto Automator", "identifier": "com.omni-automation.oo.merge-column-to-topic", "version": "1.3", "description": "The action will merge the contents of the selected column to the Topic column. If no column is selected, a list of column titles is presented.", "label": "Merge into Topic Column", "shortLabel": "Merge to Topic" }*/ (() => { var action = new PlugIn.Action(function(selection, sender){ var topicColumn = document.outline.outlineColumn var noteColumn = document.outline.noteColumn var textColumns = new Array() columns.forEach(column => { if ( column.type === Column.Type.Text && column != topicColumn && column != noteColumn ){textColumns.push(column)} }) if(textColumns.length === 0){ new Alert("MISSING RESOURCE","No text columns to merge.").show() console.error("MISSING RESOURCE: ","No text columns to merge.") return "No text columns to merge." } var chooseColumnFlag = false if ( selection.columns === undefined || selection.columns.length === 0 || selection.columns.length > 1 || selection.columns[0] === topicColumn ){ chooseColumnFlag = true var textColumnsTitles = textColumns.map(column => {return column.title}) var textColumnsTitlesIndexes = new Array() textColumnsTitles.forEach((item,index) => { textColumnsTitlesIndexes.push(index) }) var columnTitlesMenu = new Form.Field.Option( "columnTitles", "Column", textColumnsTitlesIndexes, textColumnsTitles, 0 ) } // CONSTRUCT THE FORM var form = new Form() // CREATE FORM ELEMENTS var columnTitleCheckbox = new Form.Field.Checkbox( "shouldUseColumnTitle", "Use column title for Topic column title", false ) var replaceContentCheckbox = new Form.Field.Checkbox( "shouldReplaceContent", "Replace existing Topic content (To append content, leave unchecked)", false ) var seperatorStringMenu = new Form.Field.Option( "appendingString", null, [0,1], ["Append with Space","Append with New Line"], 0 ) // ADD ELEMENTS TO FORM if(chooseColumnFlag){form.addField(columnTitlesMenu)} form.addField(columnTitleCheckbox) form.addField(replaceContentCheckbox) form.addField(seperatorStringMenu) // SHOW THE FORM AND RETURN JAVASCRIPT PROMISE formPrompt = "Merge Options:" buttonTitle = "Continue" formPromise = form.show(formPrompt, buttonTitle) // VALIDATE FORM CONTENT form.validate = function(form){ // RETRIEVE CHOSEN VAUES var shouldReplaceContent = form.values['shouldReplaceContent'] if(chooseColumnFlag === false){ var fieldsLength = 3 var targetFieldIndex = 2 } else { var fieldsLength = 4 var targetFieldIndex = 3 } if(shouldReplaceContent && form.fields.length === fieldsLength){ form.removeField(form.fields[targetFieldIndex]) } else if (!shouldReplaceContent && form.fields.length === fieldsLength - 1) { var seperatorStringMenu = new Form.Field.Option( "appendingString", null, [0,1], ["Append with Space","Append with New Line"], 0 ) form.addField(seperatorStringMenu) } return true } // PROCESS THE FORM RESULTS formPromise.then(function(form){ // RETRIEVE CHOSEN VAUES var selectedColumn if(chooseColumnFlag === false){ var selectedColumn = selection.columns[0] } else { var chosenColumnTitleIndex = form.values['columnTitles'] var chosenColumnTitle = textColumnsTitles[chosenColumnTitleIndex] var selectedColumn = columns.byTitle(chosenColumnTitle) } var selectedColumnTitle = selectedColumn.title var shouldUseColumnTitle = form.values['shouldUseColumnTitle'] var shouldReplaceContent = form.values['shouldReplaceContent'] if(!shouldReplaceContent){ var appendingString = form.values['appendingString'] var seperator = (appendingString === 0) ? ' ' : "\n" } var topicValue rootItem.descendents.forEach(item => { var cellValue = item.valueForColumn(selectedColumn) if (cellValue === null){cellValue = ''} if (shouldReplaceContent){ item.topic = cellValue.string } else { topicValue = (item.topic === null) ? '': item.topic if(topicValue === ''){ item.topic = cellValue.string } else { item.topic = topicValue + seperator + cellValue.string } } }) if(shouldUseColumnTitle){topicColumn.title = selectedColumnTitle} selectedColumn.remove() }) // PROCESS FORM CANCELLATION formPromise.catch(function(error){ console.log("form cancelled", error) }) }); action.validate = function(selection, sender){ // validation code return true }; return action; })();
merged-columns-doc merged-columns-doc-iOS
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.

DISCLAIMER