Copy link to clipboard
Copied
Copy link to clipboard
Copied
Copy link to clipboard
Copied
Copy link to clipboard
Copied
Copy link to clipboard
Copied
Copy link to clipboard
Copied
OK, I'm confused. Harbs said:
Be very, very careful with that property! The textFrameIndex is counted
by columns NOT text frames. If you have a two column frame, it
increments the textFrameIndex by 2 and three; 3 etc.
So, if all your text frames are the same number of columns, you can work
things out. If there's some single column frames and some multi-column
frames, the textFrameIndex property is all but useless!
Is this really still a problem in CS5?:

The textFrameIndex properties of the 3 frames are 0,1, and 2, as noted in the above output from my javascript shell.
I would have thought from Harbs' description that they'd be 0, 1, 4 or 0,3,5 or somesuch?
Copy link to clipboard
Copied
John,
I just tested that with CS3, CS4, CS5 and CS5.5:
app.activeDocument.textFrames.everyItem().textFrameIndex;
+ your 3 threaded text frames (first one 1 column, second one 3 columns, third one 2 columns)
Results:
CS3: 4,1,0
CS4: 4,1,0
CS5: 2,1,0
CS5.5: 2,1,0
Obviously this bug was fixed in CS5.
Uwe
Copy link to clipboard
Copied
Copy link to clipboard
Copied
Does anybody know if this bug was ever fixed? I've come across this post, Dave, because I was using your script from 2005 to divide a story into two text sets of linked text frames, and it was crashing occasionally. In general, it works perfectly -- thank you for that -- but ever so rarely it crashes. I did a little debugging and discovered that the textFrameIndex property is a little squirrelly and sometimes has a value greater than the number of textContainers in the story.
It is clear from this series of posts that this crash is happening when some of the boxes containing the story have more than one column.
Does anybody know if there's a quick way to get the information that the textFrameIndex property should be giving us? Of course a little function could be made which comes up with that value, by compensating for all the extra columns that occur in boxes of the chain before the one you want the index of -- and that's what I'll do right now, I guess -- but it seems a little ridiculous.
- Richard
Copy link to clipboard
Copied
Or even simpler, just count them, like this:
TextFrame.prototype.realTextFrameIndex = function(){
var i;
var myStory;
myStory = this.parentStory;
for (i=0; i < myStory.textContainers.length; i++)
if (myStory.textContainers == this)
return i;
}
You shouldn't have to worry about whether the "for" loop will terminate without an "i" having been returned, because that will never happen, right?
Copy link to clipboard
Copied
That didn't seem to work, so I'm going to go with the slightly less elegant, non-prototype version:
function real_text_frame_index (myFrame) {
var i;
var myStory;
myStory = myFrame.parentStory;
for (i=0; i < myStory.textContainers.length; i++)
if (myStory.textContainers == myFrame)
return i;
}
This totally works, and now the divide story script works perfectly. Thanks again, Dave.
Copy link to clipboard
Copied
And thanks to Harbs for pointing out this bug.
Copy link to clipboard
Copied
This version is probably a little more efficient:
function real_text_frame_index (frame) {
var tfs = frame.parentStory.textContainers.slice();
for (var i=0; i < tfs.length; i++){
if (tfs == frame){return i}
}
return NaN;
}
Harbs
Copy link to clipboard
Copied
Right, because arrays require less overhead than collections.
Thanks again.
Copy link to clipboard
Copied
Actually, textContainers is an Array, but resolving it on each iteration is expensive...
Harbs
Copy link to clipboard
Copied
How the memory fades. I just discovered this bug again.
At least this thread tells me that I can indeed depend on getting 0,1,3,5,7, etc from the particular story I'm dealing with.
Dave
Copy link to clipboard
Copied
There's another method of finding a text frame's index in its story. It has the advantage of being much, much quicker, especially when you're dealing with a frame with a high index.
Disadvantage: imagine a text frame has no text in it (frame.texts.length == 0) because the frame's too small to hold the text at that point, so it is skipped. The script below gets tripped up when you're trying to find the index of such a frame. But if the frame in question has text, but previous text frames in the thread had texts.length == 0, then it still counts perfectly well. So to get round this, the function call to doError() below could be replaced by Harbs' method. More code; on average, faster execution. Maybe someone more experienced at scripting InDesign could find a more elegant solution?
function getTextFrameIndex(frame) {
if (frame.texts.length == 0) doError();
var frameCharInd = frame.texts[0].index;
if (frameCharInd == 0) return 0;
var textRange = frame.texts[0].parentStory.characters.itemByRange(0, frameCharInd).getElements()[0];
return textRange.parentTextFrames.length - 1;
}
Copy link to clipboard
Copied
PaulR72 wrote:
There's another method of finding a text frame's index in its story. It has the advantage of being much, much quicker, especially when you're dealing with a frame with a high index. (...)
Hi Paul,
I didn't notice that your routine is 'much, much quicker' than Harbs' original patch. In fact, Harbs' method may take time or may be very fast depending on how near is the target index from the starting point (0), because it uses an ascendant loop. I tried both methods by selecting the 60th frame of a story, and Harbs seems to remain the quickest…
Anyway, I think we can improve the looping strategy by exploiting the fact that:
realTextFrameIndex <= frame.textFrameIndex
This is clue that allows us to position the initial index closer —on average case— of the actual result, and to use a descendant loop:
function realTextFrameIndex(frame)
//------------------------------------------------
// Improvement of Harbs' method
{
var tfs = frame.parentStory.textContainers,
col = 1 + frame.textFrameIndex,
i = tfs.length;
// This generally will speed up the process
// because we know that realTextFrameIndex < col
// ---
if( col < i ) i = col;
while( i-- )
{
if( frame == tfs ) return i;
}
return NaN;
}
@+
Marc
Copy link to clipboard
Copied
Nice improvement!
It's not gonna get much better than that!
Marc gets the prize! ![]()
Harbs
Copy link to clipboard
Copied
Paul,
I haven't profiled your script, but I see one problem, and another possible cause of slowness.
Problem: The script will only work if the text frame has text. (Possibly even all of them. I'm not sure what you'll get if there's an empty frame in the middle.)
Performance bottleneck: You access Text objects 6 times. Depending on how complex the text is, this could add many milliseconds to the script, so you might actually have to wait a blink and a half instead of a blink... ![]()
Harbs
Copy link to clipboard
Copied
Hiya Marc,
Well now I'm confused too. I did the time tests again just today and the method in my post was faster than Harbs' method, even when selecting the third frame in a long story: 3213 vs. 10283 microseconds. The 60th frame has a much more exaggerated difference.Your new method took 4800 microseconds to find the third frame.
Could that be because I'm running CS4? I think it might explain our different results. Pretty sure that I'm using $.hiresTimer properly.
Paul
Copy link to clipboard
Copied
Pretty sure that I'm using $.hiresTimer properly.
Are you sure it's not wrapping? Check Date.now().
Copy link to clipboard
Copied
John, by wrapping, do you mean exceeding maximum setting of hiresTimer and advancing again through 0? If so, very sure it's not wrapping, because max setting for hiresTimer is many seconds, and the scripts execute almost immediately. Or am I misunderstanding you??
Copy link to clipboard
Copied
Hmm. I had a strange memory of $.hiresTimer offering very small
values only. But that's clearly not the case. Please disregard.
Copy link to clipboard
Copied
Hiya Harbs,
Understand what you're saying about accessing text objects. And yet ... when I select, say, even just the third text frame in one of the books I'm working on, then use $.hiresTimer to time how long it takes for the two methods to find the index, the method that I posted before is quicker. I gave the results in my previous post. It's quicker even for just the third frame; and it's much, much quicker when dealing with frames further into the book. -- I've run two different tests on separate days, and the results were quite clear, at least on my machine: CS4 on a Mac. The OS and/or InDesign version may give different results for different people.
About empty text frames. I tested it before posting my first post, and did say that if an empty frame is between the selected frame and the first one, the script still works. It just doesn't work if the empty frame is the one selected (that is, the frame you want to get the real index of). So here's the code I'm using, which is a combination of your method and of mine:
function getFrameIndex(frame) {
if (frame.texts.length == 0 || (frame.texts.length == 1 && frame.texts[0].length == 0) ) {
var textFrames = frame.parentStory.textContainers.slice();
for (var i=0; i < textFrames.length; i++) if (textFrames == frame) return i;
}
else {
var frameCharInd = frame.texts[0].index;
if (frameCharInd == 0) return 0;
var textRange = frame.texts[0].parentStory.characters.itemByRange(0, frameCharInd).getElements()[0];
return textRange.parentTextFrames.length - 1;
}
}
Paul
Find more inspiration, events, and resources on the new Adobe Community
Explore Now