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

[CS4, JS] Adding ".parent" with a while loop

New Here ,
Jan 17, 2010 Jan 17, 2010

Copy link to clipboard

Copied

Hello,

I'm trying to find out the page side of a text frame, however the text frame may be grouped. I am currently using a few if and else if statements to get to the text frame's page parent - each statement adds another ".parent", e.g.

myTextFrame = app.activeDocument.stories.paragraphs.parentTextFrames[0]

if (myTextFrame.parent.constructor.name == "Page")

    mySide = myTextFrame.parent.side

else if (myTextFrame.parent.parent.constructor.name == "Page")

    mySide = myTextFrame.parent.parent.side

etc.

Is there a more elegant way to do this? I tried to construct a while loop, e.g.


while (myTextFrame.constructor.name !== "Page")

myTextFrame = myTextFrame + ".parent"


But as I quickly found out, that concatenation won't work (I've only been using JS for about 2 months...I know, it's no excuse)!

Is there a way to do that loop correctly, i.e. add ".parent" to the myTextFrame variable until myTextFrame.constructor.name == "Page"?

Thanks in advance for any help 🙂

TOPICS
Scripting

Views

1.9K

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 ,
Jan 17, 2010 Jan 17, 2010

Copy link to clipboard

Copied

while (myTextFrame.constructor.name != "Page")

  myTextFrame = myTextFrame.parent;

(also note: != instead of !==)

If the frame is on the pasteboard, its parent will be "Spread", and if the frame is on the pasteboard of a master page, it'll be "MasterSpread".

You might want to check for these cases as well to exit gracefully:

while (myTextFrame.constructor.name != "Page")

{

  if (myTextFrame.constructor.name == "Spread" ||

    myTextFrame.constructor.name == "MasterSpread")

  {

     alert ("Exit with grace.");

    exit(0);

  }

  myTextFrame = myTextFrame.parent;

}

Checked with this mini-script; select something with the pointer and run it to see what its parent looks like:

alert (app.selection[0].constructor.name+"\n"+app.selection[0].parent.constructor.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
Guide ,
Jan 17, 2010 Jan 17, 2010

Copy link to clipboard

Copied

Here is a generic OOP approach:

TextFrame.prototype.getPage = function()
// -----------------------------------------------
// Returns the containing Page of this TextFrame
{
var p = this.parent,
     pc;
while( pc=p.constructor )
     {
     if( pc == Page )
          return p;
     if( pc == Spread || pc == MasterSpread )
          throw Error("The textframe is placed on a spread!");
     if( 'parentTextFrames' in p && !(p=p.parentTextFrames[0]) )
          throw Error("The textframe's container overflows!");
     p=p.parent;
     }
}

// Sample code (assuming a text frame is selected)
// -----------------------------------------------
var tf = app.selection[0],
     pg;
     
try {
     pg = tf.getPage();
     alert( "Page: " + pg.name + " Side: " + pg.side);
     }
catch(e)
     {
     alert( e );
     }

@+

Marc

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
Guide ,
Jan 17, 2010 Jan 17, 2010

Copy link to clipboard

Copied

However, the code above does not answer to the 'Group problem'.

If the target text frame is embedded within a Group, the getPage() method will return the containing Page of the group itself (i.e. the containing page of the center point of the group). In this case, how to get the page wich apparently owns the text frame subobject? Interesting challenge...

@+

Marc

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
LEGEND ,
Jan 17, 2010 Jan 17, 2010

Copy link to clipboard

Copied

Marc Autret wrote:

Interesting challenge...


Yes, it is...

I think the only way to take care of that, would be to compare the bounds of the text frame with that of the resulting page...

Harbs

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
Guide ,
Jan 18, 2010 Jan 18, 2010

Copy link to clipboard

Copied

Harbs. wrote:

I think the only way to take care of that, would be to compare the bounds of the text frame with that of the resulting page...

You're right! So we need a subroutine in the getPage method. If the resulting page doesn't contain this (comparing page.bounds and this.visibleBounds), then we request the page.parent spread and we loop in spread.pages to find the page wich matches this. Not so hard.

@+

Marc

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
Guide ,
Jan 18, 2010 Jan 18, 2010

Copy link to clipboard

Copied

Now the code:

Page.prototype.intersects = function(/*PageItem bounds*/pib)
// -----------------------------------------------
// Return true if this page intersects the bounds pib
{
var b = this.bounds;
return b[0]<=pib[2] && pib[0]<=b[2] && b[1]<=pib[3] && pib[1]<=b[3];
}

TextFrame.prototype.getPage = function()
// -----------------------------------------------
// Returns the containing Page of this TextFrame
// [Works also with grouped/embedded frame]
{
var p = this.parent,
   b = this.visibleBounds,
   pc, pgs, i;
while( pc=p.constructor )
   {
   if( pc == Page )
      {

      if( p.intersects(b) ) return p;
      pgs = p.parent.pages; // spread pages
      for( i=pgs.length-1 ; i>=0 && p=pgs ; i-- )
         {
         if( p.intersects(b) ) return p;
         }
      pc = Spread;
      }
   if( pc == Spread || pc == MasterSpread )
      throw Error("The textframe is placed on a spread!");
   if( 'parentTextFrames' in p && !(p=p.parentTextFrames[0]) )
      throw Error("The textframe's container overflows!");
   p=p.parent;
   }
}

// Sample code (assuming a text frame is selected)
// -----------------------------------------------
var tf = app.selection[0],
   pg;
  
try {
   pg = tf.getPage();
   alert( "Page: " + pg.name + " Side: " + pg.side);
   }
catch(e)
   {
   alert( e );
   }

@+

Marc

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
LEGEND ,
Jan 18, 2010 Jan 18, 2010

Copy link to clipboard

Copied

Hey, Marc, shouldn't the second part of this test:

if( 'parentTextFrames' in p && !(p=p.parentTextFrames[0]) )

Be "p==" rather than assignment ("p=")? Either that or I guess I'm not sure what the purpose of the assignment is...

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
Guide ,
Jan 18, 2010 Jan 18, 2010

Copy link to clipboard

Copied

Hi John,

I agree the syntax looks weird but we really need that surprising assignment.

My code:

if( 'parentTextFrames' in p && !(p=p.parentTextFrames[0]) )

   {

   /* do something */

   }

is actually a shortcut for:

if( 'parentTextFrames' in p )

   {

   p = p.parentTextFrames[0];

   if( !p )

      {

      /* do something */

      }

   }

The interesting fact to notice is that the parentTextFrames property of a Text object returns an empty collection when the text falls out of range within an overflowing frame.

@+

Marc

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
LEGEND ,
Jan 18, 2010 Jan 18, 2010

Copy link to clipboard

Copied

LATEST

The interesting fact to notice is that the parentTextFrames

property of a Text object returns an empty collection when the

text falls out of range within an overflowing frame.

No. It's an empty Array. parentTextFrames is an Array -- not a

collection. That's why you can check for parentTextFrames[0] without

getting an error.

Harbs

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