3 Replies Latest reply on May 4, 2014 6:20 PM by Marg123

    return information about insertion point


      Okay, I'm really sorry if this question is either obvious or already been asked. I've scoured the forum, but I can't find the answer. That said, I'm not too experienced with InDesign scripting, so I may have seen it and not realized.

      Anyway, my problem concerns trying to access the underlying xml structure in a document. Our workflow is such that the typesetter imports XML into a new document, creates a bunch of new styles that correspond to the names of the xml elements, and than maps them. After laying out the document, he then exports the xml for re-use later.

      This all works well, but for the fact that inside the post-exported xml we need refrerences to the actual page numbers. I've written a script (a section of which is below, this is VERY beta) that inserts the page number into the text of a text frame so that, when the xml is exported, the page references will travel with it. This works well, except that sometimes the page number is inserted outside the tag. More specifically, this happens when a new paragraph begins a new page (since each paragraph is its own element).

      So, my questions boils down to: is it possible to get any information about a particular insertion point? In all the solutions I've attempted (returning the associated xmlElement, returning the paragraph style, moving the insertion point so that it's inside the text) InDesign seems to be ignoring the underlying XMLstructure.


      Thanks for an help anyone can provide. Also, feel free to harangue me if the question is unclear. Like I said, I'm pretty new here.




      var doc = app.documents.item(0);

      var pageCount = doc.pages.length;



        // beginning at the end of the document, start looping thorough each page 

          for (var j = pageCount-1; j > 0; j--) {

              //create temporary frame to hold page number

              var tempFrame = doc.pages[j].textFrames.add();

              var origPageNumber = tempFrame.parentPage.name;

              //check whether we're in FM or body of MS

              if (parseInt(origPageNumber)) {

                  var pageNumber = (parseInt(origPageNumber));

                  //check how many digits and how many zeros to add

                  if(pageNumber<10){pageNumber = "00" + pageNumber;}

                  if(pageNumber>10 && pageNumber<100){pageNumber = "0" + pageNumber;}     

                  if(pageNumber>=100){pageNumber = pageNumber;} 

              } else {

                  pageNumber = origPageNumber;


              //insert number into temporary frame

              tempFrame.contents = "[pbr-" + pageNumber +"]";

              tempFrame.paragraphs[0].appliedCharacterStyle = doc.characterStyles.item("pbr-insert");

              //check wheter there's a text frame on the page. If there is, move the page number into it.

              if (doc.pages[j].textFrames.length != 1 && doc.pages[j] != prevPage) {

                  try {

                      var selectedFrame = doc.pages[j].textFrames[1];

                      var prevPage = doc.pages[j];

                      tempFrame.paragraphs[0].move(LocationOptions.before, selectedFrame.insertionPoints.item(1));


                  catch (e) {








        • 1. Re: return information about insertion point
          Marc Autret Level 4

          Hi Marg123,


          There are many interesting points to highlight here:


          • First of all, beware of a minimalistic parseInt(…) call especially when you supply strings that may contain leading zeroes (which seems to be a possible issue in your project). A good practice is to always provide the radix (10) as second argument. Indeed, parseInt("013") will return 11 (octal-based parsing) while parseInt("013", 10) will return 13 as expected.


          • I don't get the purpose of neither your prevPage variable, or sending the activePage command in your code (?) Maybe I missed something. Anyway I don't think you need that odd try...catch workaround. Just loop in pages and do what is expected, depending on your requirements.


          • Also, creating/removing a temporary TextFrame to pre-format each page tag doesn't seem necessary to me. It's very time consuming. Work with Characters.itemByRange(…) to apply a style to the newly inserted text. Just meticulously calculate character indices basing on the insertion point and the length of the string you're inserting.


          • Now about insertion points. Compared to other Text-based objects, InsertionPoint is in fact really easy to use because any text container has always, at least, one insertion point, whatever special states as empty frames, overset contents, etc. So, except for tables and cells (weird wisdom!) you can always consider myTextFrame.insertionPoints[0] as reliable and returning what you are excepting, including in threaded frame context. What can be critical in some scripts is the need of absolutely resolving the IP specifier—viz, myTextFrame.insertionPoints[0].getElements()[0]—in order to have a solid path, relative to the parent Story, in case frame contents is changing during the process.


          • Finally, your algorithm doesn't make clear that you take a critical option about page looping order:


          (a) If you loop from last to first page (your choice), you authorize that inserted tags can shift to the right during recomposition in threaded frames, but you make sure that those page number tags actually reflect the original layout (before tag insertions).


          (b) Conversely, if you loop from first to last page, each tag will appear at the very beginning of its target frame, and therefore will reflect the final layout, which may differ from the original one.


          I tried to gather these principles, comments, and options in the code below to make things clearer:


          // YOUR SETTINGS
          // ---
          const PG_NUM_PATTERN = "[pbr-%1]",
                PG_NUM_STYLE_NAME = "pbr-insert",
                LOOP_DIRECTION = +1;                               // +1: first->last pg  ;  -1: last->first pg
          // YOUR PROCESS
          // ---
          (function pageNumberProcess(doc)
              var loopMethod = LOOP_DIRECTION < 0 ? 'pop' : 'shift',
                  pgTagStyle,                                       // CharacterStyle -- style of page tag
                  a,                                                // Array     -- array of all doc's pages
                  pg,                                               // Page      -- current page
                  tf,                                               // TextFrame -- current target
                  pgName,                                           // String    -- current page name (as read from the DOM)
                  pgNumber,                                         // String    -- formatted page number
                  pgTag,                                            // String    -- the whole page tag
                  ip,                                               // InsertionPoint -- temp IP
                  i,                                                // uint      -- index of IP in its story
                  count = 0;                                        // uint      -- just a counter
              // Make sure that the tag style exists
              // ---
              if( !(pgTagStyle=doc.characterStyles.itemByName(PG_NUM_STYLE_NAME)).isValid )
                  alert( "Cannot find the character style " + PG_NUM_STYLE_NAME );
              // Loop thorough each page
              // ---
              a = doc.pages.everyItem().getElements();
              while( pg=a[loopMethod]() )
                  // Determine the target frame (if any) as the 1st one
                  // ---
                  tf = pg.textFrames.length && pg.textFrames[0];
                  if( !tf ) continue;
                  // Page number formatting stuff
                  // ---
                  pgName = pg.name;
                  pgNumber = isNaN(pgNumber=parseInt(pgName, 10)) ?  // don't forget the radix on using parseInt
                      pgName :                                       // fall back to the raw page name, or...
                      ('000'+pgNumber).substr(-3);                   // put the number in 3-digits form
                  pgTag = localize(PG_NUM_PATTERN, pgNumber);        // format the whole tag
                  // Get the IP at the very beginning of tf, and its index
                  // ---
                  ip = tf.insertionPoints[0].getElements()[0];       // getElements()[0] returns a resolved specifier
                  i = ip.index;                                      // index of ip in the parent story
                  // Insert pgTag and apply pgStyle
                  // ---
                  ip.texts[0].contents = pgTag;                      // texts[0] prevents from inserting by accident a SpecialCharacter
                      itemByRange(i, i+pgTag.length-1).
                      appliedCharacterStyle = pgTagStyle;
              alert( count + " pages have been successfully tagged." );


          Hope that helps.




          1 person found this helpful
          • 2. Re: return information about insertion point
            Marg123 Level 1

            Wow, this goes above and beyond in terms of helping me out. I really appreciate it. I'll take a look at your notes, but you definitly point out some real issues with my own code. In my defense (in as much as I can muster one) the code is sort in changing, so part of it is a hold-over from an eralier approach I was taking. Nonetheless, thanks again, and I'll let you  know shorrtly what I find.

            • 3. Re: return information about insertion point
              Marg123 Level 1

              Sure enough, your advice was enormously helpful, and I agree that using a separate text frame to format the string is unnecessary, bulky, and potentially problematic. Also, to follow up one on your last point about the order in which I'm looping through the pages, I'm going from last to first so that I an retain the original pagination.

              Having looked at your code though, I'm still running into the same problem. I'm able to determine whether I'm inside a given frame, but I still can't determine whether I'm inside a given tag. I've included a screen shot to hep illustrate the problem.  The "Heading 1" is an <h1></h1> element, and the "Integer sapien tor..." is inside a <Txt></Txt> element. The XML itself is based on an external DTD, which has been imported and mapped.

              I want to avoid having the page reference be inserted between two tags since the xml wont validate upon export.  I've tried looping over the XMLElements to get the current tag name as well as a couple of other (failed) strategies, but I can't figure out how to return the current tag of a given string.


              Sorry if I'm being unhelpful, but any (additional) help would be really appreciated.




              <H1 aid:pstyle="H1">Heading 1</H1> [pbr-41] <Txt aid:pstyle="TxtNI" xml:lang="EN">Inter