I want to add a row via Javascript for Automation. At first I tried to create a row and push it into the document.
oo = Application("OmniOutliner");
var doc = oo.documents;
test = oo.Row({
name: "Title"
});
doc[0].rows.push(test)
This gets me Error -10000: AppleEvent handler failed..
What does it take to create a row in OO? Then I also need to attach cells, but if I can’t create a simple row, then it is pointless to ask that right now as well.
So, I think I solved the problem. I’ll post the solution since there’s a lack of examples of OmniOutliner with JXA here:
oo = Application("OmniOutliner");
oo.includeStandardAdditions = true
var doc = oo.documents;
// There's either a nasty hidden column or the noteColumn is 1-based
var noteColumn = doc[0].noteColumn.index() - 1
// Topic||Column||Column
// Just use || as separator and it should do the job for you.
var clipboard = oo.theClipboard().split('\r');
var final = [];
//Splits the clipboard items and inserts an empty string in the index of the noteColumn.
clipboard.forEach(function(el) {
var elem = el.split('||');
elem.splice(noteColumn, 0, "");
final.push(elem);
});
final.forEach(function(movie, idx) {
// Creates an empty row.
var row = oo.Row({});
// Appends the row to your document. It returns the index, so we're storing it.
var index = doc[0].rows.push(row);
// Grabs all the rows, then select the last item (which we just appended) and loop through its cells, modifying the values according to our clipboard array.
doc[0].rows()[index - 1].cells().forEach(function(cell, i) {
cell.value = movie[i];
});
});
So I appended the row, grabbed it, looped through its cells and replaced their contents.
Thanks ! Very good to see some JavaScript for Automation (JXA) examples here.
A couple of thoughts:
We can make our variables local by wrapping our code in a run() { ... code ... } function, or in an immediately executed anonymous function (function () { ... code ... })(); An advantage of doing this is that it separates our variables out into a local panel if we use the Safari JS debugger and saves us the trouble of hunting for them in the forest of global variables.
Perhaps, for clarity and reuse, we can separate out the clipboard parsing from the row creation ?
I find it quite helpful to add 'use strict'; at the start of a function. It adds some useful error messages, warning for example of variables which are undeclared (and therefore inadvertently global rather than local);
e.g. something like:
(function () {
'use strict';
// IDs of rows created from (field-delimited) text lines
// ooDoc -> String -> [ooRowID]
function lineRows(doc, strLines, rowDelim, colDelim) {
// optional arguments, falling back to defaults
rowDelim = rowDelim || /[\n\r]+/;
colDelim = colDelim || '||';
if (doc && strLines) {
var lstLines = lineRecords(strLines, rowDelim, colDelim),
rows = doc.rows,
iFirstCol = doc.topicColumn.index(),
lstRows = [];
lstLines.forEach(function (lstLine, i) {
var iRow = rows.push(
oo.Row({
topic: lstLine[0],
note: '\n'
})
) - 1,
cells = rows.at(iRow).cells;
// Remaining columns
lstLine.slice(1).forEach(function (strField, j) {
if (strField) {
cells.at(j + iFirstCol).value = strField;
}
});
lstRows.push(iRow);
});
return rows.slice(lstRows[0], lstRows.slice(-1)[0]).id();
} else return [];
}
// String and optional row/field delimiters -> array of arrays
// (lines of fields)
// String -> String -> String -> [[String]]
function lineRecords(str, rowDelim, colDelim) {
// optional arguments, falling back to defaults
rowDelim = rowDelim || /[\n\r]+/;
colDelim = colDelim || '||';
return str.split(rowDelim).map(function (r) {
return r.split(colDelim);
});
}
// MAIN
var oo = Application("OmniOutliner"),
docs = oo.documents,
doc = docs.length ? docs.at(0) : undefined;
oo.includeStandardAdditions = true;
// Array of row IDs of any new rows created in front document
return doc ? lineRows(doc, oo.theClipboard()) : [];
})();