Monday, July 30, 2007

 

Adding a Column of Numbers

This morning, while working on an invoice, I once again found myself needing to add a column of numbers, so I decided to write a script to do it:
//DESCRIPTION: Add selected column of numbers

if (app.documents.length > 0 && app.selection.length > 0) {
  addSelection(app.selection[0]);
}

function addSelection(sel) {
  var myLines = sel.contents.split("\r");
  var total = 0;
  for (var j = 0; myLines.length > j; j++) {
    total = total + getNumber(myLines[j]);
  }
  app.activate()
  prompt("Result", String(total));
  
  function getNumber(text) {
    var start = text.search(/\d/);
    if (start == -1) return 0;
    return Number(text.slice(start));
  }
}
Notice the use of search to locate the first digit in the string representing the contents of each line (for which I might have chosen a wiser variable name than "text"). I chose to use the prompt style of alert to simplify copying the result to another application or even into an InDesign document. And, I issued an activate to bring InDesign to the front so that should I be running the script from ESTK, the prompt would be brought in front of the ESTK window.

Now I'm looking at the script, I find myself thinking: what if the column was a column within a table? I reckon there's room for a part 2 to this blog entry!

Tuesday, July 24, 2007

 

Get the Lead out!

The question was asked in the U2U forum: what does it mean in the InDesign CS3 Object Model Viewer (available from ESTK 2's Help menu) when a property is described as having the value "any"?

Well, the answer to that specific question is that "any" is a poor choice of terminology. "Varies" or "various" would be better choices.

Generally speaking, when a property is described as having a value of type "any", what it means is that you can set the value with any of a set of variable types, but what you'll get when you query the value is usually always the same type of variable; that variable type that most closely matches the property's nature.

And that led me to recall a function I've used countless times to get the leading of a text object (more precisely, the leading of the first character the text object -- unless the object is a single insertionPoint, in which case you get its leading), where two different kinds of value can be returned by the property:
function getLeading(text) {
  var leading = text.leading;
  if (leading == Leading.auto) {
    leading = text.pointSize * text.autoLeading/100;
  }
  return leading
}
Actually, this can be used to get the leading of paragraph styles, too.

For character styles, you have to be a tad careful because you could have a paragraph style where either the leading or the pointSize (or both) are set to be ignored (in which case you get the value NothingEnum.nothing), so you could use this function for character styles, but you'd be better off constructing one that addresses these other possibilities.

Saturday, July 21, 2007

 

Change of Heart about Kick-offs

For a long time, I've had a couple of "kick-off" snippets in my iSnip file that form a framework for kicking off a script. They look like this:

Document Kick-off

if (app.documents.length == 0) { exit() }
processDocument(app.documents[0]);

function processDocument(aDoc) {

} // end processDocument

Selection Kick-off

if (app.documents.length == 0 || app.selection.length == 0) { exit() }
processSelection(app.selection[0]);

function processSelection(sel) {

}

Change of Heart

I used to like this approach. Detecting immediately that the application was not in the state of interest for the script and exiting just seemed an appropriate way to get rid of those conditions without cluttering up your script with an extra level of indenting.

But there are two problems with this:
  1. There is no extra level of indenting since I switched to doing all the processing in a function. That thinking dates back to the days when I was writing monolithic scripts that did all (or most) of the work at the global level.
  2. When you use exit(), you don't just exit the script, you exit the scripting system. So, if you are trying to string together a series of scripts, the use of exit by one script prevents any more scripts in the string from running.
As a result of these two realizations, I have changed my snippets to look like this:

Document Kick-off

if (app.documents.length > 0) {
  processDocument(app.documents[0]);
}

function processDocument(aDoc) {

} // end processDocument

Selection Kick-off

if (app.documents.length > 0 && app.selection.length > 0) {
  processSelection(app.selection[0]);
}

function processSelection(sel) {

}
Notice the change from logical OR to logical AND in the selection kick-off. This structure works because if there is no document, the logical expression evaluates to false without the need to evaluate the second part of the expression, which would, in that case, cause an error.

The extra level of indenting that I used to worry about lasts just one line now, so it is not nearly the big deal it used to be.

This page is powered by Blogger. Isn't yours?