Exit
  • Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
  • 한국 커뮤니티
0

Index of textFrame in Story

Enthusiast ,
Feb 09, 2009 Feb 09, 2009
Given myTF is a textFrame, how would I find out the index of that text frame relative to the parentStory?
TOPICS
Scripting
4.2K
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
Feb 09, 2009 Feb 09, 2009
There's a property called, wait for it, wait for it ... textFrameIndex

Ta-da!

I went looking for it just the other day. I thought it would have been called storyOffset or something like that, but I was reduced to stepping down the list of textFrame properties until I found it.

Dave
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Feb 09, 2009 Feb 09, 2009
Perfect!

I never thought it would be that simple or I would've looked through the
properties myself, thanks Dave!
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Feb 09, 2009 Feb 09, 2009
Dave_Saunders@adobeforums.com wrote:
> There's a property called, wait for it, wait for it ... textFrameIndex
>

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!

--
Harbs
http://www.in-tools.com
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Feb 10, 2009 Feb 10, 2009
Very interesting, thank for the heads up!
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
May 16, 2011 May 16, 2011

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?:

multicol.png

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?

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 17, 2011 May 17, 2011

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

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
Feb 10, 2009 Feb 10, 2009
OH BOY!

Surely that's a bug!

I'm going to check with my sources.

Dave
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
May 05, 2010 May 05, 2010

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

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
May 05, 2010 May 05, 2010

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?

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
May 05, 2010 May 05, 2010

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.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
May 05, 2010 May 05, 2010

And thanks to Harbs for pointing out this bug.


Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
May 09, 2010 May 09, 2010

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

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
May 10, 2010 May 10, 2010

Right, because arrays require less overhead than collections.

Thanks again.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
May 10, 2010 May 10, 2010

Actually, textContainers is an Array, but resolving it on each iteration is expensive...

Harbs

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Advocate ,
Aug 16, 2010 Aug 16, 2010

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

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
May 13, 2011 May 13, 2011

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;
}

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guide ,
May 16, 2011 May 16, 2011

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

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
May 16, 2011 May 16, 2011

Nice improvement!

It's not gonna get much better than that!

Marc gets the prize!

Harbs

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
May 17, 2011 May 17, 2011

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

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
May 16, 2011 May 16, 2011

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

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
May 16, 2011 May 16, 2011

Pretty sure that I'm using $.hiresTimer properly.

Are you sure it's not wrapping? Check Date.now().

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
May 16, 2011 May 16, 2011

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??

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
May 16, 2011 May 16, 2011

Hmm. I had a strange memory of $.hiresTimer offering very small

values only. But that's clearly not the case. Please disregard.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
May 17, 2011 May 17, 2011
LATEST

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

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines