Skip to main content
Ian Proudfoot
Legend
February 20, 2017
Answered

Trying to understand element selection limitations

  • February 20, 2017
  • 2 replies
  • 1261 views

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

This topic has been closed for replies.
Correct answer frameexpert

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;

}

2 replies

4everJang
Legend
February 21, 2017

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.

frameexpert
Community Expert
frameexpertCommunity ExpertCorrect answer
Community Expert
February 20, 2017

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;

}

www.frameexpert.com
Ian Proudfoot
Legend
February 20, 2017

Perfect thank you Rick.

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

Ian

Legend
February 21, 2017

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