23 Replies Latest reply on Jul 3, 2009 3:29 AM by Peter Kahrel

    Coming to grips with Footnotes

    Dave Saunders Level 4

      I'm charged with writing a script to draw vertical lines next to marked paragraphs. The question arises, what if one of those paragraphs is a footnote? And further, what it said footnote overflows from one frame to another?

       

      So, I'm doing my usual thing and going back to first principles and trying things out. I'm also studying the relevant parts of the OMV. Already, I seem to have found an inconsistency. It has to do with the parent property of a footnote. The OMV says that the parent can be one of: XmlStory, Story, TextFrame or InsertionPoint.

       

      This of course requires some interpretation because the OMV lists as a possible parent any object that can own a collection of the subject objects. This explains why InsertionPoint is on the list. But a quick test leaves me wondering why all text objects aren't on the list. I created a text frame in a new document and labeled it "MainStory". I put a couple of footnotes into the fourth paragraph and ran this:

       

      var myStory = app.documents[0].textFrames.item("MainStory").parentStory;
      var myPara = myStory.paragraphs[3];
      $.writeln(myStory.footnotes.length);
      $.writeln(myPara.footnotes.length);

       

      Based on the OMV, I was expecting to get 2 in the JS console and then an error. But instead, I got 2 twice in the console and no error. A quick look at Paragraph objects confirms that they can indeed own footnote collections.

       

      This will be one of those topics where I talk to myself. ...

        • 1. Re: Coming to grips with Footnotes
          Dave Saunders Level 4

          Now that I've discovered that any text item can own footnotes, it means I can address the same footnote in more than one way. So, let's try that and see what the parent is in each case:

           

          var myStory = app.documents[0].textFrames.item("MainStory").parentStory;
          var myPara = myStory.paragraphs[3];
          $.writeln(myStory.footnotes[0].parent.constructor.name);
          $.writeln(myPara.footnotes[0].parent.constructor.name);

           

          Lo! This writes "Story" to the console twice.

           

          I think this conclusively proves that set footnotes are parented only by a Story object.

           

          Even though they've been around for a while, I'm not entirely sure I know how to create an XmlStory object, but I suspect that if one of those had footnotes in it, then it would be the parent. But I don't think there are any other possibilities. ...

          • 2. Re: Coming to grips with Footnotes
            Dave Saunders Level 4

            From the perspective of wanting to work with existing footnotes (which is what I'm setting out to do) it is of somewhat academic interest to work out how to add a footnote by script, but what the hey. This:

             

            var myStory = app.documents[0].textFrames.item("MainStory").parentStory;
            var myPara = myStory.paragraphs[3];
            var myNewFootnote = myPara.insertionPoints[-2].footnotes.add();

             

            adds an empty footnote which I could then populate. Notice that I took advantage of the fact that all the parameters of the Footnotes.add() method are optional. But I suspect that that is true only if it's a collection associated with an insertionPoint that's being added to. Let's try some other calls and see what happens:

             

            var myStory = app.documents[0].textFrames.item("MainStory").parentStory;
            var myPara = myStory.paragraphs[3];
            var myNewFootnote = myStory.footnotes.add();

             

            Wow! That worked. It added an empty footnote at the end of the story. In that case, it's hardly worth trying any other possibilities because it's clear that in the absence of parameters the footnote is added at the end of the text object.

             

            Oh, this is interesting:


            var myStory = app.documents[0].textFrames.item("MainStory").parentStory;
            var myPara = myStory.paragraphs[3];
            var myNewFootnote = myPara.insertionPoints[-2].footnotes.add({contents:"This is a test"});

             

            That created a new footnote all right and gave it a footnote reference of 3 (I've been deleting all these empty ones after I created them) but the note contains only "This is a test" and does not have the reference number. Let's look at the contents of one of the other footnotes that I manually seeded into the document:

             

            var myStory = app.documents[0].textFrames.item("MainStory").parentStory;
            var myPara = myStory.paragraphs[3];
            $.writeln(myStory.footnotes[0].contents);

             

            That resulted in:

             

                A paragraph is a text object.

             

            in the console. Where the first character (not visible in the forum) must be some kind of marker used by InDesign to indicate it's a footnote number, then there's a tab and then the contents that I'd previously typed. Checking my document's Footnote Options, I see that I had indeed called  for a tab separator.

             

            I wonder what happens if I feed the contents of one note into a new one:


            var myStory = app.documents[0].textFrames.item("MainStory").parentStory;
            var myPara = myStory.paragraphs[3];
            var myNewFootnote = myPara.insertionPoints[-2].footnotes.add({contents:myStory.footnotes[0].contents});

             

            Well, that gives me the tab but not the footnote number. Clearly, this is not the way to go about setting the contents of the text of a footnote. There's the clue. It's not the contents of the footnote I want to set but the contents of the text of the footnote:

             

            var myStory = app.documents[0].textFrames.item("MainStory").parentStory;
            var myPara = myStory.paragraphs[3];
            var myNewFootnote = myPara.insertionPoints[-2].footnotes.add();
            myNewFootnote.texts[0].contents = "This is a test."

             

            So much for logical thinking! This gives the same result as just setting the contents.

             

            Off to do some more studying. ...

            • 3. Re: Coming to grips with Footnotes
              Dave Saunders Level 4

              Well, this was pretty obvious:

               

              var myStory = app.documents[0].textFrames.item("MainStory").parentStory;
              var myPara = myStory.paragraphs[3];
              var myNewFootnote = myPara.insertionPoints[-2].footnotes.add();
              myNewFootnote.texts[0].insertionPoints[-1].contents = "This is a test."

               

              however, that does seem to say that you can't create a footnote and populate it with text in one fell swoop.

               

              Enough on creating them. Now I have to research how to work out where they are. The simple cases are easy, it's when you get into multi-column frames and footnotes that split from one area to another that things become interesting.

              • 4. Re: Coming to grips with Footnotes
                Harbs. Level 6

                >

                however, that does seem to say that you can't create a footnote and 

                populate it with text in one fell swoop.

                 

                You should be able to just insert the footnote marker 

                (SpecialCharacters.FOOTNOTE_SYMBOL).

                 

                Harbs

                • 5. Re: Coming to grips with Footnotes
                  Dave Saunders Level 4

                  Thanks for the input Harbs, but this doesn't work:

                   

                  var myDoc = app.documents[0];

                  var myStory = myDoc.textFrames.item("MainStory").parentStory;

                  var myPara = myStory.paragraphs[3];

                  var myNewFootnote = myPara.insertionPoints[-2].footnotes.add({contents:"This is a test"});

                  myNewFootnote.insertionPoints[0].contents = SpecialCharacters.footnoteSymbol;

                  myNewFootnote.insertionPoints[1].contents = myDoc.footnoteOptions.separatorText;

                   

                  The attempt to insert the symbol does nothing and so the separator appears between the "T" and "h" of "This".

                   

                  Dave

                  • 6. Re: Coming to grips with Footnotes
                    Harbs. Level 6

                    Hmm.

                     

                    You're right. I wonder why that is...

                     

                    FWIW, I just checked how I've created footnotes in the past, and I did 

                    it in two steps...

                     

                    Harbs

                    • 7. Re: Coming to grips with Footnotes
                      Peter Kahrel Adobe Community Professional & MVP

                      >I wonder why that is...

                       

                      That's because of the generally misconceived behaviour of specialCharacters when combined with other strings. If you do this (with an insertion point):

                       

                      app.selection[0].contents = SpecialCharacters.enDash = "x";

                       

                      you don't get –x (an en-dash followewed by x) but the special character's enumeration value followed by x: 1397059140x.

                       

                      This is wrong. If it were corrected, you should be able to do something like this:

                       

                      var myNewFootnote = myPara.insertionPoints[-2].footnotes.add({contents: SpecialCharacters.footnoteSymbol + myDoc.footnoteOptions.separatorText + "This is a test"});

                       

                      But now you get 1399221837. This is a test

                       

                      (or whatever the separator text is instead of ". ").

                       

                      So it's nothing to do with footnotes or the footnoteSymbol special character, but with the fact that specialCharacters can't be strung together with other strings.

                       

                      Peter

                      • 8. Re: Coming to grips with Footnotes
                        Harbs. Level 6

                        Yes I know that. However, InsertionPoint.contents = 

                        SpecialCharacters.footnoteSymbol does not work either...

                         

                        Harbs

                        • 9. Re: Coming to grips with Footnotes
                          Dave Saunders Level 4

                          Right Peter, that's why I didn't do that.

                           

                          I attempted to do it in two steps but it looks as though you can't willy-nilly add footnote references to text. Which makes sense if you think about it.

                           

                          Dave

                          • 10. Re: Coming to grips with Footnotes
                            Dave Saunders Level 4

                            Getting back to my original need (locating the footnote), I ran this:

                             

                             

                            myDoc = app.documents[0];

                            myStory = myDoc.textFrames.item("MainStory").parentStory;

                            myFootnote = myStory.footnotes[0];

                            for (var j in myFootnote) {

                            $.writeln(j + ": " + myFootnote[j]);

                            }

                             

                             

                            And that produced this in the JavaScript Console (I deleted the spurious "Execution completed" line from the middle):

                             

                             

                            storyOffset: [object InsertionPoint]

                            contents:   A paragraph is a text object.

                            allPageItems:

                            allGraphics:

                            id: 257

                            label:

                            isValid: true

                            parent: [object Story]

                            index: 0

                            properties: [object Object]

                            textColumns: [object TextColumns]

                            textStyleRanges: [object TextStyleRanges]

                            texts: [object Texts]

                            paragraphs: [object Paragraphs]

                            lines: [object Lines]

                            words: [object Words]

                            characters: [object Characters]

                            insertionPoints: [object InsertionPoints]

                            textVariableInstances: [object TextVariableInstances]

                            pageItems: [object PageItems]

                            ovals: [object Ovals]

                            rectangles: [object Rectangles]

                            graphicLines: [object GraphicLines]

                            textFrames: [object TextFrames]

                            polygons: [object Polygons]

                            groups: [object Groups]

                            hiddenTexts: [object HiddenTexts]

                            This particular set of properties basically says that a footnote is a container of text and as such you can get at the objects that might be contained in the text or are part of the text. But it also says that it is associated with a story via the parent property and the storyOffset property. I expect that the story offset insertion point is actually the one after the marker in the text. Let's check. ...

                            • 11. Re: Coming to grips with Footnotes
                              Dave Saunders Level 4

                              Nope. Wrong again. The insertion point is the one before the footnote reference marker in the story as this script demonstrates. Run it and it selects the reference marker:

                               

                              myDoc = app.documents[0];

                              myStory = myDoc.textFrames.item("MainStory").parentStory;

                              myFootnote = myStory.footnotes[0];

                              app.select(myStory.characters[myFootnote.storyOffset.index]);

                               

                              Dave

                              • 12. Re: Coming to grips with Footnotes
                                Dave Saunders Level 4

                                This script:

                                 

                                myDoc = app.documents[0];

                                myStory = myDoc.textFrames.item("MainStory").parentStory;

                                myFootnote = myStory.footnotes[0];

                                $.writeln("Paragraphs: " + myFootnote.paragraphs.length);

                                $.writeln("Characters: " + myFootnote.characters.length);

                                $.writeln("Insertion Points: " + myFootnote.insertionPoints.length);

                                $.writeln("Words: " + myFootnote.words.length);

                                $.writeln("Lines: " + myFootnote.lines.length);

                                $.writeln("Text Style Ranges: " + myFootnote.textStyleRanges.length);

                                $.writeln("Text Columns: " + myFootnote.textColumns.length);

                                 

                                Returns:

                                 

                                Paragraphs: 1

                                Characters: 31

                                Insertion Points: 32

                                Words: 7

                                Lines: 1

                                Text Style Ranges: 1

                                Text Columns: 0

                                 

                                Which has me wondering:

                                 

                                a) Can a footnote ever have more than one paragraph?

                                b) What happens if you use a column-relative anchoring spec for an anchored object in a footnote?

                                 

                                Dave

                                • 13. Re: Coming to grips with Footnotes
                                  Dave Saunders Level 4

                                  Yes indeed, a footnote can have more than one paragraph.

                                   

                                  Hello, it even appears possible to put a table into a footnote.

                                   

                                  Dave

                                  • 14. Re: Coming to grips with Footnotes
                                    Dave Saunders Level 4

                                    Yes it is. And even though footnote objects don't have table collections, you can get at the table collection by using:

                                     

                                    myFootnote.texts[0].tables;

                                     

                                    Dave

                                    • 15. Re: Coming to grips with Footnotes
                                      Harbs. Level 6

                                      Yes indeed, a footnote can have more than one paragraph.

                                      >

                                      Hello, it even appears possible to put a table into a footnote.

                                       

                                      A footnote is for all practical intents and purposes basically the 

                                      same concept as a story...

                                       

                                      Harbs

                                      • 16. Re: Coming to grips with Footnotes
                                        Dave Saunders Level 4

                                        Understood. But a story has a tables collection.

                                         

                                        And I see that the story's table collection doesn't include the one in the footnote, so there was I thinking you could get at all tables in a document via the document's story collection but it turns out to not be true; as well as check for nested tables, you also have to look for tables in footnotes.

                                         

                                        Dave

                                        • 17. Re: Coming to grips with Footnotes
                                          Dave Saunders Level 4

                                          Now here's a question: is it true that a footnote always starts in the same text column as the reference in the story? It is easy enough to construct a scenario where a footnote is too long and so has to expand to the next column, but is there ever a case where the footnote itself might start in a later column?

                                           

                                          I've not tried it, but what if you have two footnotes at the same point in the text where the first one is very long? Would that create the scenario? I guess I need to do some more experiments.

                                           

                                          Dave

                                          • 18. Re: Coming to grips with Footnotes
                                            Dave Saunders Level 4

                                            No, it does not appear to be possible. Rather than split the first footnote, the two are locked together by virtue (I presume) of being in the same line of text. Consequently, it is possible for an oversized footnote in this scenario to bring about a permanent overset condition.

                                             

                                            Dave

                                            • 19. Re: Coming to grips with Footnotes
                                              Dave Saunders Level 4

                                              So, the question becomes: how to detect that a footnote has flowed to the next column? Notice that a footnote has no text columns. If you try to get at them by accessing the text columns of the text, you'll be disappointed:

                                               

                                              myDoc = app.documents[0];

                                              myStory = myDoc.textFrames.item("MainStory").parentStory;

                                              myFootnote = myStory.footnotes[1];

                                              $.writeln(myFootnote.texts[0].textColumns.length);

                                               

                                              returns zero (even though I've artificially extended the footnote to take about one and a quarter columns.

                                               

                                              What about parent text frames -- the footnote might not have any but the text surely does:

                                               

                                              myDoc = app.documents[0];

                                              myStory = myDoc.textFrames.item("MainStory").parentStory;

                                              myFootnote = myStory.footnotes[1];

                                              $.writeln(myFootnote.texts[0].parentTextFrames.length);

                                               

                                              returns one. The footnote might spread across to the second column, but that's still in the same text frame. For the sake of completeness, let me make the note even longer. And now it returns two. So, if a footnote is long enough to spread to a second text frame, then the parentTextFrames property of the text of the footnote gives you some information.

                                               

                                              Do we have to resort to comparing coordinates to crack this issue? The basic problem with such an approach is one of speed. But maybe there's no other choice.

                                               

                                              Aha! Remember the question I asked about column-relative anchored objects? Well, the good news is that they do follow the columns of the text frame and are not dependent on the textColumns. That means that by temporarily putting such an anchored item at the start of every line in a footnote one can track its locations to find out where the text flows and so avoid having to deal with text coordinates which can be affected by such things and indents, alignment, and even worse, oversized tables or inlines.

                                              • 20. Re: Coming to grips with Footnotes
                                                Harbs. Level 6

                                                Hi Dave,

                                                 

                                                You should be able to use the textFrame bounds, horizontal offset, and 

                                                the textFramePreferences.textColumnFixedWidth along with the 

                                                textFramePreferences.textColumnCount to figure out which column text 

                                                falls out...

                                                 

                                                That's a whole lot better than playing around with anchored objects!

                                                 

                                                Harbs

                                                • 21. Re: Coming to grips with Footnotes
                                                  Dave Saunders Level 4

                                                  Maybe, but there are some really sticky issues related to some of the way-out cases (wide tables or inlines, for example). Still, my method falls on its nose if the frame is rotated or skewed.

                                                   

                                                  Dave

                                                  • 22. Re: Coming to grips with Footnotes
                                                    Harbs. Level 6

                                                    Wide tables and inlines are about the only far out cases possible.

                                                     

                                                    As long as the text is limited to not being in one such creature, it's 

                                                    a pretty reliable (and quick) method.

                                                     

                                                    I personally have never come across a wide table or inline which 

                                                    extrudes a text column in a footnote.

                                                     

                                                    Rotated or skewed frames with footnotes are pretty rare as well...

                                                     

                                                    Harbs

                                                    • 23. Re: Coming to grips with Footnotes
                                                      Peter Kahrel Adobe Community Professional & MVP

                                                      > However, InsertionPoint.contents = SpecialCharacters.footnoteSymbol does not work either...

                                                       

                                                      Ah, right -- so there is an (additional) issue with footnoteSymbol.

                                                       

                                                      Peter