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
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 🙂
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);
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
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
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
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
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
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...
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
Copy link to clipboard
Copied
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