9 Replies Latest reply on Feb 22, 2017 6:28 AM by Russ Ward

    Trying to understand element selection limitations

    Ian Proudfoot Level 3

      I have created an ExtendScript which is used to install structured application definitions the first time that a script is run. Here's what it does:

      1. Opens a copy of a structapps.fm file that contains the required XML application definitions.
      2. Creates a backup of the local structapps file.
      3. Opens the local structapps file.
      4. Delete any XML applications with names that match the new XML apps.
      5. Copies the new XML apps into the local structapps file.
      6. Reads the structapps file using fmDispatcher, saves and closes the files.

       

      This all works very well up to a point. Where I have a problem is with the insertion point for the copied XML applications. I want to insert them directly after the <Version> element.

      I can do that when there are other following <XMLApplication> elements. However if there are no following elements it inserts the copied elements before the <Version> element which is invalid. Here's the code:

      function copyXApps(localStrappDoc, sourceStrappDoc)
      {
          var copyApps, ser = new ElementRange(), ter = new ElementRange(), copyApps, target,
          sourceElem = sourceStrappDoc.MainFlowInDoc.HighestLevelElement.FirstChildElement.NextSiblingElement;
          target = localStrappDoc.MainFlowInDoc.HighestLevelElement.FirstChildElement.NextSiblingElement;
          
          if(sourceElem === null || sourceElem.ObjectValid() === false) return;
          
              ser.beg.parent = ser.end.parent = sourceElem.ParentElement; 
              ser.beg.child = sourceElem;
              ser.end.child = sourceElem.ParentElement.LastChildElement;
              
              ser.end.parent = sourceElem.ParentElement;
              ser.beg.offset = 0;
              ser.end.offset = 0;
              
          //Set the document element selection.
          sourceStrappDoc.ElementSelection = ser;
          copyApps = sourceStrappDoc.Copy (0);
          
          if (copyApps === Constants.FE_Success){
              ter.beg.parent = ter.end.parent = target.ParentElement;
              ter.beg.child = ter.end.child = target;
              ter.beg.offset = ter.end.offset = 0;
              
              //Set insertion point for copied Xapps, then paste:
              localStrappDoc.ElementSelection = ter;
              pasteApps = localStrappDoc.Paste (0);
      
      
              return pasteApps;
             }
          }
      
      
      

       

      There's also a problem with the selection code which selects all apps except the last one despite using LastChildElement. I seem to be misunderstanding something here.

      Thanks for any help.

      Ian

        • 1. Re: Trying to understand element selection limitations
          frameexpert Level 4

          Hi Ian,

           

          I adapted the functions below from FDK functions that I got from Russ Ward years ago. You call the getElementRangeConstants function to set up some constants for the getElementRange function to use. You pass it an element (in your case, the Version element) and the desired location (in your case, AFTER_ELEMENT) and it rerturns an ElementRange. I have used this function and a FrameScript variation for years without any problems. Please let me know if you have any questions or comments. Thanks.

           

          -Rick

           

          function getElementRange (element, location) {
              
              var elementRange = new ElementRange;
              
              switch (location) {
                  
                  case BEFORE_ELEMENT :
                      elementRange.beg.parent = element.ParentElement;
                      elementRange.beg.offset = 0;
                      elementRange.beg.child = element;
                      elementRange.end.parent = element.ParentElement;
                      elementRange.end.child = element;
                      elementRange.end.offset = 0;
                      break;
                  
                  case AFTER_ELEMENT :
                      elementRange.beg.parent = element.ParentElement;
                      elementRange.beg.offset = 0;
                      elementRange.beg.child = element.NextSiblingElement;
                      elementRange.end.parent = element.ParentElement;
                      elementRange.end.child = element.NextSiblingElement;
                      elementRange.end.offset = 0;
                      break;
                  
                  case BEGINNING_OF_BRANCH :
                      elementRange.beg.parent = element;
                      elementRange.beg.offset = 0;
                      elementRange.beg.child = element.FirstChildElement;
                      elementRange.end.parent = element;
                      elementRange.end.child = element.FirstChildElement;
                      elementRange.end.offset = 0;
                      break;
                  
                  case END_OF_BRANCH :
                      elementRange.beg.parent = element;
                      elementRange.beg.offset = 0;
                      elementRange.end.parent = element;
                      elementRange.end.offset = 0;
                      break;
                  
                  case SELECT_ELEMENT :
                      if (element.NextSiblingElement.ObjectValid()) {
                          elementRange.beg.parent = element.ParentElement;
                          elementRange.beg.child = element;
                          elementRange.end.parent = element.ParentElement;
                          elementRange.end.child = element.NextSiblingElement;
                      }
                      else {
                          elementRange.beg.parent = element.ParentElement;
                          elementRange.beg.child = element;
                          elementRange.beg.offset = 0;
                          elementRange.end.parent = element.ParentElement;
                          elementRange.end.offset = 0;
                      }
                      break;
                      
                  case SELECT_CONTENTS :
                      if (element.FirstChildElement.ObjectValid()) {
                          elementRange.beg.parent = element;
                          elementRange.beg.child = element.FirstChildElement;
                          elementRange.beg.offset = 0;
                          elementRange.end.parent = element;
                          elementRange.end.offset = 0;
                      }
                      else {
                          elementRange.beg.parent = element;
                          elementRange.beg.offset = 0;
                          elementRange.end.parent = element;
                          elementRange.end.offset = Constants.FV_OBJ_END_OFFSET;
                      }
                      break;
              }
          
              return elementRange;
          }
          
          function getElementRangeConstants () {
              
              BEFORE_ELEMENT = 1;
              AFTER_ELEMENT = 2;
              BEGINNING_OF_BRANCH = 3;
              END_OF_BRANCH = 4;
              SELECT_ELEMENT = 5;
              SELECT_CONTENTS = 6;
          }
          
          1 person found this helpful
          • 2. Re: Trying to understand element selection limitations
            Ian Proudfoot Level 3

            Perfect thank you Rick.

            This does exactly what I need and will be even more useful for my next project!

             

            Ian

            • 3. Re: Trying to understand element selection limitations
              Russ Ward Level 4

              Rick, thanks for the attribution. The truth is, unless you are much smarter than me, you need to get a function like this set up and then just use it. You might look over that code and think "wow, Russ sure knows this stuff" but the truth is that it is still quite cryptic to me. All I did was spend an hour manually setting up the different types of selections, while querying the ElementSelection property to see how it was set up. Then I built the function to model the behavior that I saw. All these years later, I still don't really understand the logic of the ElementRange structure. I could probably get it if I really studied hard, but my ignorance has not hindered me yet. So, heck with it.

               

              Russ

              • 4. Re: Trying to understand element selection limitations
                frameexpert Level 4

                I have a similar development style, except it usually takes me more than an hour :-). I keep banging on it until it works; my understanding of it may come later. Many of my functions are black boxes to me--I know they work so I use them with confidence, even if I sometimes forget the logic behind them.

                 

                That said, I appreciate all of your excellent plugins and code samples and your willingness to share them. You have helped me solve a lot of problems over the years.

                 

                Here is one from my wishlist. Saxon recently released its XSLT engine for JavaScript. It's meant primarily for use in a web server but it would be fantastic if it could be used with ExtendScript.

                • 5. Re: Trying to understand element selection limitations
                  4everJang Level 3

                  Ian,

                   

                  There is also another method to get the copy into the right location, using text locations:

                   

                  oPgf = oDoc.MainFlowInDoc.FirstTextFrameInFlow.FirstPgf;

                  if( oPgf.NextPgfInFlow.ObjectValid( )

                       oTLoc = new TextLoc( oPgf.NextPgfInFlow, 0 );

                  else

                       oTLoc = new TextLoc( oPgf, Constants.FV_OBJ_END_OFFSET);

                  oTRange = new TextRange( oTLoc, oTLoc );

                  oDoc.TextSelection = oTRange;

                  oDoc.Paste( true );

                   

                  This may not work in generic cases where you want to get the element location just right, but in this particular case it is all the code you need.

                  1 person found this helpful
                  • 6. Re: Trying to understand element selection limitations
                    4everJang Level 3

                    Hi Rick,

                     

                    I was looking for that a while ago, as I am doing almost everything in XML and XSLT now. After much asking and not giving up, I did get the info from the dev team in India about calling the XSLT processor from ExtendScript. I will prepare a post about it. I can send you the code, too.

                     

                    Ciao

                    • 7. Re: Trying to understand element selection limitations
                      frameexpert Level 4

                      Jang, that would be fantastic. Thank you. -Rick

                      • 8. Re: Trying to understand element selection limitations
                        Ian Proudfoot Level 3

                        Hi Russ,

                        You did much better than me on getting a working understanding! I tried to match the reported element locations with a script that reported everything to the console. Unfortunately that didn't return the information that I expected...

                         

                        Ian

                        • 9. Re: Trying to understand element selection limitations
                          Russ Ward Level 4

                          Here is a general purpose function I use to report the current element selection, text selection, and/or graphic selection. I think every developer needs some version of something like this.

                           

                          function cm_ReportIds(doMsgBox, doConsole)
                          {
                              var msg = "";
                              var doingBook = false;
                              var file = app.ActiveDoc;
                              
                              if(!file.ObjectValid())
                              {
                                  file = app.ActiveBook;
                                  doingBook = true;
                              }
                              
                              if(!file.ObjectValid()) 
                              {
                                  alert ("No active document or book.");
                                  return;
                              }
                          
                              msg += "----------------------------------------\n";
                              if(doingBook)    
                                  msg += "ACTIVE BOOK: ";
                              else   
                                  msg += "ACTIVE DOCUMENT: \n\n"
                              msg += file.Name + "\n(ID: " + file.id + ")\n";
                              msg += "----------------------------------------\n\n";
                             
                              msg += "----------------------------------------\n";
                              msg += "CURRENT ELEMENT SELECTION (er = file.ElementSelection):\n\n";
                              
                              var er = file.ElementSelection;
                              
                              if(!er.beg.parent.ObjectValid() &&
                                  !er.beg.child.ObjectValid() &&
                                  !er.end.parent.ObjectValid() &&
                                  !er.end.child.ObjectValid())
                              {
                                  msg += "(No valid element selection)\n";
                              }
                              
                              else
                              {
                                  msg += "er.beg.parent (element):  ";
                                  if(er.beg.parent.ObjectValid())
                                      msg += "<" + er.beg.parent.ElementDef.Name + ">      (ID: " + er.beg.parent.id + ")\n";
                                  else msg += "-NONE-\n";
                                  
                                  msg += "er.beg.child (element):    ";
                                  if(er.beg.child.ObjectValid())
                                      msg += "<" + er.beg.child.ElementDef.Name + ">      (ID: " + er.beg.child.id + ")\n";
                                  else msg += "-NONE-\n";
                                  
                                  msg += "er.beg.offset: " + er.beg.offset + "\n\n";
                                  
                                  msg += "er.end.parent (element):  " ;
                                  if(er.end.parent.ObjectValid())
                                      msg += "<" + er.end.parent.ElementDef.Name + ">      (ID: " + er.end.parent.id + ")\n";
                                  else msg += "-NONE-\n";
                                  
                                  msg += "er.end.child (element):    ";
                                  if(er.end.child.ObjectValid())
                                      msg += "<" + er.end.child.ElementDef.Name + ">      (ID: " + er.end.child.id + ")\n";
                                  else msg += "-NONE-\n";
                                  
                                  msg += "er.end.offset: " + er.end.offset + "\n";
                              }
                              msg += "----------------------------------------\n\n";
                          
                              if(!doingBook)
                              {
                                  msg += "----------------------------------------\n";
                                  msg += "CURRENT TEXT SELECTION (tr = file.TextSelection):\n\n";
                                  
                                  var tr = file.TextSelection;
                                  
                                  if(tr.beg.obj.ObjectValid())
                                  {
                                      msg += "tr.beg.obj (pgf ID):  " + tr.beg.obj.id + "\n";
                                      msg += "tr.beg.obj (pgf format):  " + tr.beg.obj.Name + "\n";
                                      msg += "tr.beg.offset:  " + tr.beg.offset + "\n\n";
                                      
                                      msg += "tr.end.obj (pgf ID):  " + tr.end.obj.id + "\n";
                                      msg += "tr.end.obj (pgf format):  " + tr.end.obj.Name + "\n";
                                      msg += "tr.end.offset:  " + tr.end.offset + "\n";
                                  }
                                  else msg += "(No valid text selection)\n";
                                  msg += "----------------------------------------\n\n";
                          
                                  msg += "----------------------------------------\n";
                                  msg += "CURRENT GRAPHIC SELECTION:\n\n";
                                 
                                 var graphic = file.FirstSelectedGraphicInDoc;
                                 var path = "";
                                  
                                  if(graphic.ObjectValid())
                                  {
                                      msg += "Selected graphic object: ";
                                      if(graphic.constructor.name == "AFrame")
                                      {
                                          msg += "Anchored frame       (ID: " + graphic.id + ")\n";
                                          var elem = graphic.Element;
                                          if(elem.ObjectValid())
                                          {
                                              msg += "Anchored frame element:  <" +
                                                  elem.ElementDef.Name + ">    (ID: " + elem.id + ")\n";
                                          }
                                          msg += "First graphic object in the frame: ";
                                          
                                          graphic = graphic.FirstGraphicInFrame;
                                          if(graphic.ObjectValid())
                                          {
                                              msg += graphic.constructor.name + "       (ID: " + graphic.id + ")\n";
                                              if(graphic.constructor.name == "Inset")
                                                  path = graphic.InsetFile;
                                          }
                                          else msg += "(none detected)";
                                      }
                                  
                                      else
                                      {
                                          msg += graphic.constructor.name + "       (ID: " + graphic.id + ")\n";
                                          if(graphic.constructor.name == "Inset")
                                              path = graphic.InsetFile;
                                          
                                          msg += "Parent anchored frame: ";
                                          
                                          graphic = graphic.FrameParent;
                                          if(graphic.ObjectValid() && graphic.constructor.name == "AFrame")
                                          {
                                              msg += "  ID: " + graphic.id + "\n";
                                              var elem = graphic.Element;
                                              if(elem.ObjectValid())
                                              {
                                                  msg += "Anchored frame element:  <" +
                                                      elem.ElementDef.Name + ">    (ID: " + elem.id + ")\n";
                                              }
                                          }
                                          else msg += "(none detected)";
                                      }
                                  
                                      if(path != "")
                                      {
                                          msg += "\nReferenced graphic filepath:\n" + path + "\n";
                                      }
                                  }            
                                  
                                  else msg += "(No valid graphic selection)\n";
                                  msg += "----------------------------------------\n\n";
                              }
                              
                              if(doMsgBox)
                                  alert(msg);
                              if(doConsole)
                              {
                                  while(msg.length > 0)
                                  {
                                      Err(msg.substring(0, 255));
                                      msg = msg.substring(255, msg.length);
                                  }
                              }
                          }
                          
                          
                          1 person found this helpful