24 Replies Latest reply on May 17, 2011 5:45 PM by PaulR72

    Index of textFrame in Story

    Fred Goldman Level 3
      Given myTF is a textFrame, how would I find out the index of that text frame relative to the parentStory?
        • 1. Re: Index of textFrame in Story
          Level 1
          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
          • 2. Re: Index of textFrame in Story
            Fred Goldman Level 3
            Perfect!

            I never thought it would be that simple or I would've looked through the
            properties myself, thanks Dave!
            • 3. c
              Harbs. Level 6
              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
              • 4. c
                Fred Goldman Level 3
                Very interesting, thank for the heads up!
                • 5. Re: Index of textFrame in Story
                  Level 1
                  OH BOY!

                  Surely that's a bug!

                  I'm going to check with my sources.

                  Dave
                  • 6. Re: Index of textFrame in Story
                    richardh6 Level 1

                    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

                    • 7. Re: Index of textFrame in Story
                      richardh6 Level 1

                      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[i] == 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?

                      • 8. Re: Index of textFrame in Story
                        richardh6 Level 1

                        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[i] == myFrame)

                                    return i;

                        }

                         

                         

                        This totally works, and now the divide story script works perfectly.  Thanks again, Dave.

                        • 9. Re: Index of textFrame in Story
                          richardh6 Level 1

                          And thanks to Harbs for pointing out this bug.


                          • 10. Re: Index of textFrame in Story
                            Harbs. Level 6

                            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[i] == frame){return i}
                                }
                                return NaN;
                            }
                            

                             

                            Harbs

                            • 11. Re: Index of textFrame in Story
                              richardh6 Level 1

                              Right, because arrays require less overhead than collections.

                               

                              Thanks again.

                              • 12. Re: Index of textFrame in Story
                                Harbs. Level 6

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

                                 

                                Harbs

                                • 13. Re: Index of textFrame in Story
                                  Dave Saunders Level 4

                                  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

                                  • 14. Re: Index of textFrame in Story
                                    PaulR72

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

                                    • 15. Re: Index of textFrame in Story
                                      Marc Autret Level 4

                                      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[i] ) return i;
                                                }
                                      
                                           return NaN;
                                      }
                                      

                                       

                                      @+

                                      Marc

                                      • 16. Re: Index of textFrame in Story
                                        Harbs. Level 6

                                        Nice improvement!

                                         

                                        It's not gonna get much better than that!

                                         

                                        Marc gets the prize!

                                         

                                        Harbs

                                        • 17. Re: c
                                          John Hawkinson Level 5

                                          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?

                                          • 18. Re: Index of textFrame in Story
                                            PaulR72 Level 1

                                            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

                                            • 19. Re: Index of textFrame in Story
                                              John Hawkinson Level 5

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

                                               

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

                                              • 20. Re: Index of textFrame in Story
                                                PaulR72 Level 1

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

                                                • 21. Re: Index of textFrame in Story
                                                  John Hawkinson Level 5

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

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

                                                  • 22. Re: c
                                                    Laubender Adobe Community Professional & MVP

                                                    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

                                                    • 23. Re: Index of textFrame in Story
                                                      Harbs. Level 6

                                                      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

                                                      • 24. Re: Index of textFrame in Story
                                                        PaulR72 Level 1

                                                        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[i] == 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