• Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
    Dedicated community for Japanese speakers
  • 한국 커뮤니티
    Dedicated community for Korean speakers
Exit
0

Algorithm for navigating an element selection

Community Expert ,
Jan 25, 2017 Jan 25, 2017

Copy link to clipboard

Copied

Hi All,

Given a selected element anywhere in a document:

var doc = app.ActiveDoc;

var element = doc.ElementSelection.beg.child;

I can touch every element in the tree using a function like this:

var elements = getElements (element, /^xref$/, []);

function getElements (element, nameRegex, elements) {

    if (element.ElementDef.ObjectValid ()) {

        if (nameRegex.test (element.ElementDef.Name)) {

            elements.push (element);

        }

    }

    var element2 = element.FirstChildElement;

    while (element2.ObjectValid ()) {

        elements = getElements (element2, nameRegex, elements);

        element2 = element2.NextSiblingElement;

    }

    return elements;

}

This particular function traverses the selected element and its descendants and gets elements matching a particular regular expression. What is important is that it uses recursion to touch every element in the tree.

I have a different situation where there may be a series of sibling elements selected and I want to still touch every element in the selection. The selection might look something like this:

structureview.png

Notice that there is no top-level, containing element selected. But I still want to touch every element in the selection. I am looking for a general purpose algorithm for doing this. Thank you very much.

-Rick

TOPICS
Scripting

Views

546

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

Mentor , Jan 26, 2017 Jan 26, 2017

Hi Rick,

Here is some code that should get you most of the way there. The GetSelectedElements() function will get all top-level selected elements. For example, it will get the <em>, (text node), <footnote>, (text node), etc. from your sample. You should be able to easily modify it or use it in conjunction with your current function to get all descendants too.

I believe that function accounts for any nature of element selection, including a single element, multiple siblings, a text selection only,

...

Votes

Translate

Translate
Mentor ,
Jan 26, 2017 Jan 26, 2017

Copy link to clipboard

Copied

Hi Rick,

Here is some code that should get you most of the way there. The GetSelectedElements() function will get all top-level selected elements. For example, it will get the <em>, (text node), <footnote>, (text node), etc. from your sample. You should be able to easily modify it or use it in conjunction with your current function to get all descendants too.

I believe that function accounts for any nature of element selection, including a single element, multiple siblings, a text selection only, and insertion point only, and selected table cells without any full row selection.

By the way, for your code, did you consider element.NextElementDFS, rather than recursion?

Hope this helps. It was FDK code that I hastily converted to ES for this request. It's possible that I may have introduced a bug or two.

Russ

function elem_GetSelectedElements(oDoc, deriveElemWithoutSelection)

{

    //initialize this

    var elems = new Array();

    //get the current element selection

    var er = oDoc.ElementSelection;

 

    //also, get the selected table, if there is one

    var oTable =oDoc.SelectedTbl;

    //if we have isolated cells selected, we run an entirely different process.

    //when there are cells selected, the element range is all null. But, we

    //can find the table and go cell-by-cell, getting the selected cells and their

    //corresponding elements.

    //This will also handle the case if there is no element selection at all.

    if(!er.beg.parent.ObjectValid() && !er.end.parent.ObjectValid() &&

       !er.beg.child.ObjectValid() && !er.end.child.ObjectValid() )

    {

        //We'll only look for anything if we have a valid table.

        //Otherwise, there is no element selection and we will

        //let the array return empty

        if(oTable.ObjectValid())

        {

            var cells = GetSelectedCells(oDoc, oTable);

       

            for(var i = 0; i < cells.length; i++)

            {

                elems.push(cells.Element);

            }

        }

    }

    //If there is no parent but there is a child, the HLE is

    //selected. The child will be the HLE.

    else if(!er.beg.parent.ObjectValid() && er.beg.child.ObjectValid())

    {

        elems.push(er.beg.child);

    }

    //If the parent and child elements are the same, there is a text selection

    //or just an insertion point. If we are allowed to derive from a text selection,

    //let's do that now.

    else if(  (er.beg.parent.id == er.end.parent.id) &&

                 (  (!er.beg.child.ObjectValid() && !er.end.child.ObjectValid()) ||

                     (er.beg.child.id == er.end.child.id) ) &&

                 deriveElemWithoutSelection )   

    {

        elems.push(er.beg.parent);

    }

    //otherwise, there are one or more elements selected.

    //Let's get step down the tree and get them. Siblings only.

    else

    {

        var oElem = er.beg.child;

        //we start at the beg.child and step down through the siblings.

        //When we get to the end child,

        //we have reached the end of the selection. The end.child is not part

        //of the selection. We can always start by adding the beg.child because

        //that has to be in there.

        while(oElem.ObjectValid() && oElem.id != er.end.child.id)

        {

            elems.push(oElem);

            oElem = oElem.NextSiblingElement;

         }

    }

  return elems;

}

       

...and you'll need this too:

function tbl_GetSelectedCells(oDoc, oTable)

{

    var cells = new Array();

   

    if(!oDoc.ObjectValid())

        return cells;

   

    if(!oTable.ObjectValid())

        oTable = doc.SelectedTbl;

   

    if(!oTable.ObjectValid())

        return cells;

    var oRow = oTable.TopRowSelection;

    var bottomRowSelected = oTable.BottomRowSelection;

    var leftColSelected = oTable.LeftColNum;

    var rightColSelected = oTable.RightColNum;

    while(oRow.ObjectValid())

    {

        var i = 0;

        oCell = oRow.FirstCellInRow;

        while(oCell.ObjectValid())

        {

            if(i >= leftColSelected && i <= rightColSelected)

                cells.push(oCell);

            i++;

            oCell = oCell.NextCellInRow;

        }

        if(oRow.id == bottomRowSelected.id)

            oRow = oDoc.GetNamedColor ("InvalidateThisObject");

        else oRow = oRow.NextRowInTbl;

    }

    return cells;

}

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Mentor ,
Jan 26, 2017 Jan 26, 2017

Copy link to clipboard

Copied

In the first function, I used the wrong name for GetSelectedCells. You'll need to rename the reference or the function name.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Feb 22, 2017 Feb 22, 2017

Copy link to clipboard

Copied

LATEST

I am sorry for the delay in responding. I am finally at the point where I need this code and it works great! Thank you very much. -Rick

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines