Wednesday, February 21, 2007

 

Locating a Table Cell

They say that necessity is the mother of invention. Yesterday I was faced with needing to know the exact location of the top of a cell in a table so I could precisely position an anchored object. The x-coordinate of the cell was no problem because this table filled the column from side to side, so my anchored rectangle was easy to position horizontally, but vertically is another thing entirely.

It's worth stepping back a bit to explain what I was trying to achieve. I had two documents each with a huge table in it, over 300 rows and 7 or 8 columns. I wanted to have alternating fills but I could use the regular table features because the fills needed to be transparent so that the complex background could still be seen.

I conceived of the idea of putting an exactly sized rectangle over every other row by inserting it as an anchored item in the first character position of the first cell of each affected row. This would allow the "fill" to be transparent without the rest of the table also having to be transparent. It was the work of a moment to create the necessary object style to apply the fill and transparency and to set up the anchored object settings. But the heights of the rows vary and so the offset from the baseline of the text also needed to be calculated for each row. Here's the function I constructed to do that:
  function sizeAndPostionRect(table, row, rect) {
row.cells[0].texts[0].recompose();
var width = table.width;
var height = row.cells[0].height;
var myBounds = rect.geometricBounds;
myBounds[0] = myBounds[2] - height;
myBounds[3] = myBounds[1] + width;
rect.geometricBounds = myBounds;
var myCell = row.cells[0];
var tI = myCell.topInset
var fB = myCell.firstBaselineOffset;
myCell.firstBaselineOffset = FirstBaseline.fixedHeight;
myCell.minimumFirstBaselineOffset = 0;
myCell.verticalJustification = VerticalJustification.topAlign;
var myCellTop = myCell.texts[0].characters[1].baseline - tI;
myCell.verticalJustification = VerticalJustification.centerAlign
myCell.firstBaselineOffset = fB;
rect.anchoredObjectSettings.anchorYoffset = myCellTop - myCell.texts[0].characters[1].baseline;
}
The trick is to maneuver the baseline of the text in the cell so it sits on the top edge of the cell, then having grabbed the value, put everything back the way it was.

Tuesday, February 06, 2007

 

Selective Paragraph Style Properties Import

I'm working on two very similar posters. They are 30 x45 inches with a highly elaborate background image. So, for proofing purposes, I created a couple of documents that had the text of the posters on regular letter-sized pages. Each of these documents ran to 16 pages and each is a single very long table.

Everything started out with the same style names and definitions, but the text on one side wouldn't fit at that size, so I had to make it smaller.

So, here I am with two posters using the same styles but the text needs to be at a different size in one of them. I can't just import the styles from the proof document because the colors are wrong. All I want to do is transfer the font size and leading from the styles in the proof document to the corresponding styles in the poster.

Given that this is a one-shot script, I decided to simply open both documents with the poster at the back and the proof in front and then transfer the properties from the front document to the back. Here's the script:
//DESCRIPTION: Transfer font size and leading from styles in doc[0] to styles in doc[1]

myBackDoc = app.documents[1];
myFrontDoc = app.documents[0];
backStyles = myBackDoc.paragraphStyles.everyItem().name;
for (j = backStyles.length - 1; j > 0; j--) {
  frontStyle = myFrontDoc.paragraphStyles.item(backStyles[j]);
  if (frontStyle == null) continue;
  backStyle = myBackDoc.paragraphStyles.item(backStyles[j]);
  backStyle.pointSize = frontStyle.pointSize;
  backStyle.leading = frontStyle.leading;
}
Notice that I avoid messing with No Paragraph Style by counting down to one and not zero in the loop. Not a very remarkable script, but definitely quicker to write and more reliable than doing the job manually -- provided, of course, that I remembered which was supposed to be at the back and which at the front. I did.

Thursday, February 01, 2007

 

Arrays are Associative

I owe this technique to Peter Truskier who posted a script on the U2U forum in early January that blew me away. See Peter's post. Look at the way Peter formed that array named thePageNames. Incredible. I just never thought of doing that even though I had been aware all along that JavaScript arrays are associative.

What this means is that if you have a set of named entities and you want to filter out all the duplicates, rather than use some kind of isInArray test, you can use an associative array. For example, this morning, I wanted a list of all the paragraph style names used in a run of text. Recalling this example by Peter, I came up with this function:
function getParaStyles(text) {
    var tempArray = new Array();
    var textStyles = text.paragraphs.everyItem().appliedParagraphStyle;
    for (var j = textStyles.length - 1; j >= 0; j--) {
      tempArray[textStyles[j].name] = "";
    }
    var styles = new Array();
    for (var j in tempArray) {
      styles.push(j)
    }
    return styles
  }
I'm so pleased with this that I had to share it. Thanks a bunch Peter!

The first loop walks through all the paragraphs getting the name of the style used by the paragraph creating/setting a value (could be any value; we don't care about the value) for the element of tempArray with that name. Thus, by the end of the loop we have precisely one member of that array for each style that was present in the text.

The second loop pushes those names into a regular indexed array and returns the list of names to the calling script. Great!

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