Saturday, January 14, 2006


Updating Whole Library

I've just worked my way through a 161-page document updating some 20 figures. During the course of doing this, I created a library and popped a copy of each updated figure into the library. However, at some point, I became suspicious that the justification settings for the legend paragraph in each of these figures left something to be desired -- I was getting awful word spacing. Indeed, I needed to change them from the default (on the left) to my preferred settings (on the right) [Sorry about the space that follows -- I don't seem to have control over it.]:

Default Min. Des. Max
Word Spacing 80% 100% 133%
Letter Spacing 0% 0% 0%
Glyph Scaling 100% 100% 100%

Preferred Min. Des. Max
80% 100% 125%
-2% 0% 1%
98% 100% 101%

So, I did that. Of course, when I say "preferred" I'm talking about preferred for this particular paragraph style used in the particular way it is being used. We could have a long discussion about this, but it is a side issue as far as the script I now need is concerned.

The issue is to update the library with the latest version of each of these figures without having to step through each of the pages manually looking for them. When I created them, I labeled each of them. The script I used to move them into the library named the library items (assets in a script) for those labels. So, it ought to be as simple as interating through the page items of the document looking for the labeled item and then updating it in the library.

Well, not quite because I have another series of figures that use the same labels! Aargh. Happens, though, that in those other figures, the labeled item is a rectangle (with an image in it) while the figures I actually care about are groups. So, that makes it easy to tell one from another.

Because they're all anchored objects, though, I have to get at them indirectly -- I can't just ask for myDoc.groups. But I can ask for myStory.groups if I can get myStory pointing at the right story -- and that's easiest because it is the longest story in the document.

So, here goes:
//DESCRIPTION: Grab library elements from longest story

Document.prototype.longestStory = function() {
var myStories = this.stories.everyItem().length;
var myLim = myStories.length;
var longStory = 0;
for (var i = 0; myLim > i; i++) {
if (myStories[i] > longStory) {
var myStory = i;
longStory = myStories[i];
return this.stories[myStory]

if (app.libraries.length != 1) errorExit ("Please have exactly one library open for this script");
myDoc = app.activeDocument;
myLib = app.libraries[0];
myStory = myDoc.longestStory();
And we're all set. We have the library, the document, and the story.

But I'm starting to think I need to improve my longestStory() method. The problem is that some of my documents have a prodigious number of stories in them -- this one has 1947 stories -- and so checking the lot takes a fair amount of time. But that's for another day. Right now, I need this script fast and I don't have time for strategic improvements.

So let's gather the information we need:
myAssetNames = myLib.assets.everyItem().name;
myGroupNames = myStory.groups.everyItem().label;
That was easy. So now we need to walk down myAssetNames and find the corresponding group and update the asset. We need to allow for the possibility that the group doesn't exist in this document. The best way to do this is to add another method. This is one I lifted from the Adobe User to User InDesign_Scripting forum, although the original message seems to have disappeared into the ether.

Here's the method:
Array.prototype.indexOf = function(find,offs) {
for( var i = offs == undefined ? 0 : offs; this.length > i; i++ ) {
if( this[i]==find ) {return i}
return -1;
So, with this available to us, our main loop looks like this:
for (var j = myAssetNames.length - 1; j >= 0; j--) {
var myIndex = myGroupNames.indexOf(myAssetNames[j]);
if (myIndex != -1) {
replaceAsset(myLib, myLib.assets[j], myStory.groups[myIndex]);
And that's it, except for writing the replaceAsset(theLib, theAsset, theObject) function. Notice that this function could easily be useful in another context. That's one reason for making it a function.
function replaceAsset(theLib, theAsset, theObject) {
var theProps =
var myNewAsset =; = theProps;
And that should be that! And, indeed it was -- once I'd fixed a couple of minor typos.

Comments: Post a Comment

<< Home

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