12 Replies Latest reply on Dec 2, 2009 1:31 PM by Frame25Matt

    How do I accurately detect overset contents when using tables?

    Frame25Matt

      Hello, all. I am familiar with how to detect overset contents of a text frame, namely:

      if ( myTextFrame.parentStory.contents.length > myTextFrame.contents.length) {

        alert('There is overset text');

      } else {

        alert('There is no overset text');

      }

      However, the contents of my story are three tables, rather than text. Each table contains dozens of cells filled with text. Yet the "length" property of the frame is only 3! How do I accurately read the length of the content given that most of it is in tables so that I can test for overset text?

       

      In case it helps anyone, a more detailed description is:

       

      1. If there are three tables in the story, and only 2 fit on a page-sized text frame, the length property of that frame will be 2. Kind of weird, but not a problem yet.
      2. In the same scenario, however, if the third table BEGINS on the page but spills over (creating an overset situation), the length property of that frame will be 3 -- causing the test think there is NO overset text! InDesign simply sees 3 characters in the story, and only 3 characters on that page.
      3. When I look at the "contents" property of the story, it just reads 3 squarish characters. They're obviously some kind of special character. InDesign apparently takes the concept of "table" and just writes a placeholder character for it in the "contents" property.

       

      Am I going to have to create some routine to loop through every cell of every table and somehow add it all up to get a proper length? How do I just test for overset-ness?

       

      Thank you!

        • 1. Re: How do I accurately detect overset contents when using tables?
          Dirk Becker  Level 4

          There might be a better way, but I just constructed this expression:

           

          app.activeDocument.stories.item(0).tables.lastItem().cells.lastItem().insertionPoints.last Item().parentTextFrames.length

           

          ;-)

           

          Dirk

          • 2. Re: How do I accurately detect overset contents when using tables?
            Harbs. Level 6

            1. You are going about basic checking for overset text all wrong. Your

            method will return that text is overset if you have a story with two

            text frames. You should use the TextFrame.overflows property to check

            if it overflows.

             

            2. You have found one of the few holes in InDesign's DOM. There is no

            simple way to know if a table (or footnote) overflows. You can check

            the parentTextFrames length of the insertionPoints in the cells of the

            table, but that's not totally reliable because it will return 0 if the

            cell is overset, but also if the text in the cell cannot fit within

            the cell.

             

            Harbs

             

            Message was edited by: Harbs. for typos

            1 person found this helpful
            • 3. Re: How do I accurately detect overset contents when using tables?
              Peter Kahrel Adobe Community Professional & MVP

              >There is no simple way to know if a table overflows

               

              Well, Dirk's trick works great: if the last cell's first (or any) insertion point's parentTextFrames' length is zero, the table is overset. (Or: if the length of parentTextFrames of any of of the insertionPoints of the last cell of the table is zero, then...).

               

              Peter

              • 4. Re: How do I accurately detect overset contents when using tables?
                Peter Kahrel Adobe Community Professional & MVP

                Looks as if that works for footnotes, too:

                 

                if (myFootnote.insertionPoints[-1].parentTextFrames.length == 0)

                   // myFootnote is overset

                 

                Peter

                • 5. Re: How do I accurately detect overset contents when using tables?
                  Harbs. Level 6

                  Peter, I wrote the same thing...

                   

                  The problem is, that you get the same length of zero if the cell is placed, but the text in the cell is overset. In those situations, adding additional text frames will not accomplish anything...

                   

                  Yes, that concept works with footnotes as well. The problem is more defining if a text frame contains (continued) footnotes, since the textframe.footnotes.length will be 0...

                   

                  Harbs

                  • 6. Re: How do I accurately detect overset contents when using tables?
                    Peter Kahrel Adobe Community Professional & MVP

                    > I wrote the same thing...

                     

                    So you did! I should make a habit of reading sentences to their end -- sorry about that.

                     

                    P.

                    • 7. Re: How do I accurately detect overset contents when using tables?
                      Frame25Matt Level 1

                      Dirk's answer works perfectly, as long as the last cell does not itself contain overset text. Harbs very smartly pointed out this loophole, but at least I can control for it or work around it. So Dirk gets the Best Answer!

                       

                      Harbs' warning is rendered unnecessary in most cases anyway, and Dirk's solution will work in most cases, because cell contents (unless you have a maximumHeight set) usually expand to fit the contents, so an overset cell will be rare. But it does happen, so I wrote a bit of robust code (I hope) to account for it. (This doesn't cover footnotes, but I guess someone could write something similar for them.)

                       

                      Here is the workaround I found for Harbs' little loophole. All you have to do is temporarily delete the contents of the final cell, re-run the overflow check, and then restore the contents! But you can't just do it inside the parentStory. You have to wait until it is actually drawn on the page! (I explain why at the end.)

                       

                      Here's the code snippet:

                       

                          var cellOverset = false;
                          var finalCell = myFrameArray[0].parentStory.tables.lastItem().cells.lastItem();
                          while (finalCell.insertionPoints.lastItem().parentTextFrames.length==0) {
                              if (finalCell.contents!='' && finalCell.overflows) {
                                  cellOverset = finalCell.contents;
                                  finalCell.contents = '';
                              } else {
                                  i++;
                                  var newpage = myDocument.pages.add(); // add new page
                                  myFrameArray.push(drawTableFrame(newpage)); // draw new frame
                                  myFrameArray[i].previousTextFrame = myFrameArray[i-1]; // link new frame to previous one
                              }
                          }
                          if (cellOverset) {
                              finalCell.contents = cellOverset;
                              }
                          }

                       

                      Now, this assumes the prior existence of a myFrameArray array, which contains all the linked text frames for my page-spanning table (and which has, by this point in my code, already been loaded with the table). It also assumes the existence of my custom drawTableFrame function, which just draws a new page-wide frame. I leave all that to you.

                       

                      You'll see that it checks the final cell for having length=0, and if so, it then checks to see if the actual table cell is overflowing AND not an empty string. If so, it clears the contents of the cell and saves them, and re-runs the loop. The loop now adds the final page, links the final frame, and then after the loop exits it restores the contents of the final cell. This can only happen, by the way, after the table has been made visible again! This is because if you try to read or write cell contents that are not yet visible on the page, nothing will happen.

                       

                      Important note:

                       

                      There's another quirk (possibly bug?) anyone working with tables might want to be aware of: If the final table cell is overflowing past the visible text frame, its contents are considered empty! That's right, if you run:

                      app.activeDocument.stories.item(0).tables.lastItem().cells.lastItem().contents

                      while the cell is hidden from view, even if it is full of text it will have an empty string as its contents! But it is still considered to be overflowing. So:

                      app.activeDocument.stories.item(0).tables.lastItem().cells.lastItem().overflows

                      will return true just because it's off the text frame-- even if the contents do not actually overflow the cell boundaries. So keep that in mind when you're thinking of manipulating hidden cell contents or checking for overlows on cells that aren't yet "drawn" on the page.

                      • 8. Re: How do I accurately detect overset contents when using tables?
                        Harbs. Level 6

                        Nicely done, but be very careful with that function. The way you have it will wipe out any formatiing or inline objects in the cell...

                         

                        Harbs

                        • 9. Re: How do I accurately detect overset contents when using tables?
                          Harbs. Level 6
                          There's another quirk (possibly bug?)

                           

                           

                          No, it's not a bug. Any object not drawn will not have contents (because it really doesn't have any...).

                           

                          Harbs

                          • 10. Re: How do I accurately detect overset contents when using tables?
                            Frame25Matt Level 1

                            Harbs, you make an excellent point that overwriting the contents could possibly destroy special formatting/objects if it's not plain text. So I revised my code after realizing that manipulating the contents is actually completely unnecessary in the first place. For anyone searching for help on this issue, here is my final summary of the problem and its solution:

                             

                            Summary of problem:

                             

                            InDesign treats a table as a single special character, so it does not accurately report the "overflows" property of a text frame containing a table which spills beyond its margins. A text frame will show as not overflowing (i.e. myTextFrame.overflows will return false) if its final table simply begins within its margins--even if most of the table spills well beyond the text frame. So a ten-page table that starts on page one will only considered by InDesign scripting as being one character long (and therefore shown as fitting completely in first frame even when it doesn't). The solution for this, as discovered by Dirk, is to test whether the final cell of the table overflows.

                             

                            The solution:

                             

                            If the final cell of the table is overset (outside the margins of its containing text frame) it will be reported as overflowing (i.e. myFinalCell.overflows will return true). So we just access this cell, and check whether it overflows. However, there's a caveat: the final cell will also show as overflowing when the individual cell's contents overflow its own cell boundaries, as of course it should! So if you just test for overflow, you might end up getting a false positive. So we have to find a way to discriminate between the cases.

                             

                            To do so, we take advantage of another quirk of the way InDesign reports cell contents: if a cell is outside its containing text frame, its contents are considered empty! So all we have to do is test for both conditions, because a cell which is merely overflowing its own boundaries cannot possibly be empty.

                             

                            So the test to run is this:

                             

                            var finalCell = myTextFrame.parentStory.tables.lastItem().cells.lastItem();
                            if(finalCell.overflows && finalCell.contents=='') {  ...your code here...  }

                             

                            Of course you'll replace myTextFrame with the one you're dealing with in your own script.

                             

                            Example usage:

                             

                            This is how I implemented this in my own script. I have an array of text frames which I pass to this function, and by the time I call the function this array contains only one element, just the first large text frame (with my long table already placed inside it). It also relies on a helper function drawTableFrame which is simple and I'll leave out; it just adds a text frame to the new page and sizes it. And of course myDocument I've long ago set to be the document I'm working in.

                             

                            // Takes array of text frames, checks for overflow, and adds pages as needed
                            function addOverflowPages(whichFrameArray) {
                                var i = 0;
                                var finalCell = whichFrameArray[0].parentStory.tables.lastItem().cells.lastItem();
                                while (finalCell.overflows && finalCell.contents=='') {
                                    i++;
                                    var newpage = myDocument.pages.add(); // add new page
                                    whichFrameArray.push(drawTableFrame(newpage)); // draw new frame
                                    whichFrameArray[i].previousTextFrame = whichFrameArray[i-1]; // link new frame to previous one
                                    }
                                }

                             

                            I hope that helps someone! Thanks to everyone for pointing me in the right direction.

                            • 11. Re: How do I accurately detect overset contents when using tables?
                              Harbs. Level 6

                              I hate to burst your bubble, but if the contents of the cell is TOTALLY overset,the contents will also be empty...

                               

                              Harbs

                              • 12. Re: How do I accurately detect overset contents when using tables?
                                Frame25Matt Level 1

                                Actually, Harbs, I'd already just burst my own bubble by running additional tests! So I have to revise my whole set of instructions.

                                IGNORE EVERYTHING I WROTE ABOVE.

                                 

                                Here is the revised solution, based on the initial solution proposed by Dirk and then revised to work around Harbs bug discoveries. It is essentially a corrected version of Dirks line. Instead of saying:

                                app.activeDocument.stories.item(0).tables.lastItem().cells.lastItem().insertionPoints.last Item().parentTextFrames.length

                                you would say:

                                app.activeDocument.stories.item(0).tables.lastItem().cells.lastItem().parent.parent.insert ionPoints.lastItem().parentTextFrames.length

                                That's just the short version. Here's the full code and explanation:

                                 

                                Summary of problem:

                                 

                                InDesign treats a table as a single special character, so it does not accurately report the "overflows" property of a text frame containing a table which spills beyond its margins. A text frame will show as not overflowing (i.e. myTextFrame.overflows will return false) if its final table simply begins within its margins--even if most of the table spills well beyond the text frame. So a ten-page table that starts on page one will only considered by InDesign scripting as being one character long (and therefore shown as fitting completely in first frame even when it doesn't). The solution for this, as discovered by Dirk, is to test whether the final cell of the table is in an overflow area.

                                 

                                The solution:

                                 

                                You cannot just test whether the cell is overflowing, or whether the parent text frame is overflowing, because InDesign will misreport them and their contents when they are in an overflow area, making it impossible to distinguish a cell overflow from a containing-text-frame overflow. So we just check the parent text frame of the final insertion point, which is after the last table, and see if its length is zero (meaning has no visible contents). If so, the insertion point is in an overflow area!

                                 

                                So the test to run is this:

                                 

                                var finalCell = myTextFrame.parentStory.tables.lastItem().cells.lastItem();
                                if(finalCell.parent.parent.insertionPoints.lastItem().parentTextFrames.length==0) {  ...your code here...  }

                                 

                                Of course you'll replace myTextFrame with the one you're dealing with in your own script.

                                 

                                Example usage:

                                 

                                This is how I implemented this in my own script. I have an array of text frames which I pass to this function, and by the time I call the function this array contains only one element, just the first large text frame (with my long table already placed inside it). It also relies on a helper function drawTableFrame which is simple and I'll leave out; it just adds a text frame to the new page and sizes it. And of course myDocument I've long ago set to be the document I'm working in.

                                 

                                // Takes array of text frames, checks for overflow, and adds pages as needed
                                function addOverflowPages(whichFrameArray) {
                                    var i = 0;
                                    var finalCell = whichFrameArray[0].parentStory.tables.lastItem().cells.lastItem();
                                    while (finalCell.parent.parent.insertionPoints.lastItem().parentTextFrames.length==0) {
                                        i++;
                                        var newpage = myDocument.pages.add(); // add new page
                                        whichFrameArray.push(drawTableFrame(newpage)); // draw new frame
                                        whichFrameArray[i].previousTextFrame = whichFrameArray[i-1]; // link new frame to previous one
                                        }
                                    }

                                 

                                I hope this one is solid at last. I have tested it with empty final cell, full final cell, partially-overflowing final cell, and totally-overflowing final cell, and they all work for me. Thanks again to everyone for pointing me in the right direction!