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

(JS) Find Page of Object

Participant ,
Jan 12, 2009 Jan 12, 2009
While preparing a presentation I'm going to be giving in a couple of months, I took a good hard look at my findPage(theObj) function and I think that this is as good as it gets:
function findPage(theObj) {

if (theObj.hasOwnProperty("baseline")) {
theObj = theObj.parentTextFrames[0];
}
while (theObj != null && theObj.constructor != Page) {
var whatIsIt = theObj.constructor;
switch (whatIsIt) {
case null : return null;
case Character : theObj = theObj.parentTextFrames[0]; break;
case Cell : theObj = theObj.insertionPoints[0].parentTextFrames[0]; break;
case Application : return null;
}
if (theObj == null) return null;
theObj = theObj.parent;
}
return theObj
} // end findPage
The previous versions posted in various threads here reflected various degrees of needless caution about what might happen, for example if the object were anchored to text in a cell in an overset table. The above returns null in that case with no need for try/catch.

Notice the use of objects rather than their names. Works! This is similar to the instanceof construction but it's easier to test the negative.

If anyone can knock a hole in the above script, I'd be very interested in hearing about it.

Dave
TOPICS
Scripting
2.4K
Translate
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
Participant ,
Jan 12, 2009 Jan 12, 2009
I think I've already knocked a hole in it -- nothing like exposing stuff to public view for finding problems! With the test in the while statement for null, the null case is not possible in the switch.

Indeed, the only time that null test at the top of the loop kicks in is if the original object is overset text because of the test for null after the switch -- necessary because null doesn't have a parent.

Dave
Translate
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
Explorer ,
Jan 12, 2009 Jan 12, 2009
Hi Dave,

Objects on the pasteboard return Spread--or, at least, they used to. If your intent was to have this handled by Application, then never mind.:-)

Thanks,

Ole
Translate
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
Participant ,
Jan 12, 2009 Jan 12, 2009
Ole,

For this script, yes. If an object is on the pasteboard then it's not on a page.

Dave
Translate
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
Participant ,
Jan 12, 2009 Jan 12, 2009
I think I see why I used to include the case of Story (which returned null). If the object is a table that is overset, then its parent is the story. That winds its way up through Document and Application to get to the correct null result, so I think I'll leave it like that.

Dave
Translate
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 13, 2009 Jan 13, 2009
> If anyone can knock a hole in the above script, I'd be very interested in hearing about it.
>

What a fun challenge! ;)

Besides the unnecessary case (which you mentioned already):

1) AFAIK, every object has a valid parent, even the app itself has
itself as a parent -- itself. There's no way to get through the loop a
second time with "null".

I would do a while(theObj) without any conditions because once you made
it in, you can't get out without either returning null or getting your
page. I'd just add a case of Page and return theObj and at the end of
the function return null

2) Also, "if (theObj == null)" is probably not technically correct. "if
(theObj == undefined)" is more accurate (since the only way to get there
is with an undefined text frame). (Although I'd just use if(!theObj) for
the sake of brevity...)

3) It does not deal with references to Footnotes (although it will work
if given a reference to the text inside a footnote).

4) Your function does not deal with notes. It will not find the page a
note is on, and will error if given a reference to text inside a note.

5) You can make the function infinitely more useful by adding a second
argument which could accept any InDesign object which can contain
objects (like Spread, MasterSpread, TextFrame, etc.) I usually want to
find the location of the last text frame on overset text, so I prefer to
use (a variation of) jxswm's version of the function (which finds the
last text frame).


--
Harbs
http://www.in-tools.com
Translate
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
Participant ,
Jan 13, 2009 Jan 13, 2009
Thanks Harbs, interesting points.

1. I've resisted the use of while(theObj) because it just feels unnatural from a readability point of view. It might be worth setting up a timing test to compare the speed of it with while(theObj != null).

Your idea of moving the catch for Page into the switch is interesting. That would actually make it impossible to drop out the bottom of the while loop.

2. A test for null catches undefined values. I've always used that test, so I'm going to stay with it. Again, the form if(!theObj) strikes me as something I'd have to pause and think about for a moment each time I read it, so I tend not to use that construction.

3 & 4. Aha, I never thought about footnote references and notes. They hardly ever come up in my scripts so I hadn't had the need to think about them.

5. "infinitely"?

At one point, my version of this function did indeed return the last text frame of a story if the object were in overset text, but I ended up realizing that this was rarely useful and indeed misleading. But it is an option that is occasionally needed.

Thanks for the feedback.

Dave
Translate
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 13, 2009 Jan 13, 2009
Dave_Saunders@adobeforums.com wrote:
> Thanks Harbs, interesting points.
>
> 1. I've resisted the use of while(theObj) because it just feels unnatural from a readability point of view. It might be worth setting up a timing test to compare the speed of it with while(theObj != null).
>
>

I find (theObj) more readable, but that's probably because I have a
funny way of thinking, and don't like reading anything extra... ;)

I remember the first time I saw Kris use "0" instead of false and "1"
instead of true, it looked so odd to me, but I've gotten so used to the
short-hand way of writing everything that the long-hand way looks clumsy!

My point here was that "theObj.constructor != Page" was not necessary.
> Your idea of moving the catch for Page into the switch is interesting. That would actually make it impossible to drop out the bottom of the while loop.
>
>

Exactly. Here's (approximately) what I meant: (It should work in CS3 and
later -- in CS2 and earlier, storyOffset was a number and not a
character) Also, Notes can have a lot of nesting, and this will not
catch that...

function FindWhere(theObj,where) {
var err;
if(where==undefined){where=Page}
if (theObj.hasOwnProperty("baseline")) {
try{theObj = theObj.parentTextFrames[0];}
catch(err){}
}
while (theObj != undefined) {
var whatIsIt = theObj.constructor;
switch (whatIsIt) {
case where : return theObj;
case Note:
case Footnote: theObj = theObj.storyOffset;break;
case Character : theObj = theObj.parentTextFrames[0]; break;
case Cell : theObj =
theObj.insertionPoints[0].parentTextFrames[0]; break;
case Application : return null;
}
if (theObj == undefined) return null;
theObj = theObj.parent;
}
return null;
}

> 2. A test for null catches undefined values. I've always used that test, so I'm going to stay with it. Again, the form if(!theObj) strikes me as something I'd have to pause and think about for a moment each time I read it, so I tend not to use that construction.
>
>

Yes, I know "==null" works. My point was that if you want the
readability factor, "==undefined" is more correct -- the text frame is
undefined and not null. To illustrate this point theObj === undefined
will return true, while theObj===null returns false.
> 3 & 4. Aha, I never thought about footnote references and notes. They hardly ever come up in my scripts so I hadn't had the need to think about them.
>
> 5. "infinitely"?
>
>

Okay. "Infinitely" might be a bit of an exaggeration, but I do use
"FindWhere" on a lot of different levels. For example, it's very useful
for finding if an object is on a MasterSpread.

> At one point, my version of this function did indeed return the last text frame of a story if the object were in overset text, but I ended up realizing that this was rarely useful and indeed misleading. But it is an option that is occasionally needed.
>
>

I find it very useful indeed. I have a separate function to verify
oversets if necessary.
> Thanks for the feedback.
>
> Dave
>

--
Harbs
http://www.in-tools.com
Translate
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
Participant ,
Mar 24, 2009 Mar 24, 2009
So there I am in Sydney with this function up on the screen and it hits me that it fails to check for the possibility that the object whose page is being sought is overset text.

"As good as it gets" my foot! (Being polite for a change.)

Dave
Translate
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 ,
Mar 24, 2009 Mar 24, 2009
Well, it depends whether you want the page of the last text frame or
not. This is what I usually want, but I assumed you had wanted to return
null for overset text (as it doesn't have a page). I seem to recall
discussing this point...

--
Harbs
http://www.in-tools.com
Translate
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
Participant ,
Mar 24, 2009 Mar 24, 2009
The second line of code of the function is the problem. In fact, I wonder if I need that initial if statement at all. But the case Character line has the same problem. It must be protected by a try/catch otherwise it will fail if the text has no parentTextFrames.

Dave
Translate
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 ,
Mar 24, 2009 Mar 24, 2009
No, it won't fail. If the text is overset, the parentTextFrames[0] is
undefined. It will not fail. I was rather surprised myself when I first
noticed this, but it's very handy...

--
Harbs
http://www.in-tools.com
Translate
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
Participant ,
Mar 24, 2009 Mar 24, 2009
Hmm. Maybe I should go back to the drawing board because I discussed this in the topic.

Dave
Translate
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
Participant ,
Mar 24, 2009 Mar 24, 2009
OK, here's why it works:

array = new Array()
array[0] === undefined;

this results in true.

And, as we all know:

undefined == null!

Dave
Translate
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 ,
Mar 24, 2009 Mar 24, 2009
Ah. I didn't realize it was an array. I thought parentTextFrames was a
collection...

Yes. With Arrays it makes a lot of sense...

Thanks.

--
Harbs
http://www.in-tools.com
Translate
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 ,
Mar 24, 2009 Mar 24, 2009
LATEST
Now that I think about it, it really couldn't have been a collection...

--
Harbs
http://www.in-tools.com
Translate
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