Skip to main content
Inspiring
April 2, 2019
Answered

Get parent story of a table, row, column or cell

  • April 2, 2019
  • 1 reply
  • 5353 views

In the script I'm working on, I need to get the parent story of the selection. This will typically be a Text object which is super easy with `mySelection.parentStory`. But in many cases it could be an object that doesn't have a parentStory method, like a table, row, column or cell. If it's a table, I worked out that I can get the parent story with `mySelection.storyOffset.parentStory`, but this doesn't work for rows, columns or cells (which have no storyOffset method). I could try navigating up the DOM tree with various checks and balances, and maybe end up with something like `mySelection.parent.parent.storyOffset.parentStory`, but that seems like a crazy way to do something that I'd have thought would be simple.

Is there a simpler way?

This topic has been closed for replies.
Correct answer Kals

I had to remove my last reply, because the suggested line of code is not working.

Don't know why I thought it is, because insertionPoint has no property storyOffset.

But this will work for every selected text:

app.selection[0].insertionPoints[0].parentStory

Regardless if the text is in a table cell or not.

Tested with InDesign CC 2019 on Windows 10 and InDesign CS6 as well.

Regards,
Uwe


Laubender: So I think the best I can come up with is this variation of your idea:

var mySelection = app.selection[0];

var myStory = mySelection.hasOwnProperty("storyOffset") ? mySelection.storyOffset.parentStory : mySelection.insertionPoints[0].parentStory;

It seems to work for every possible selection.

1 reply

willcampbell7
Legend
April 2, 2019

Not that it's simple, but one way to get there is to climb up the parent tree checking for the constructor name until you find "Story".

In most cases I've encountered it seems the only time a text selection lacks the property parentStory is when the parent constructor is "Cell". So in some scripts I have code such as below, to signal when I'm inside a table.

// (assuming 'selection' is var of selected text)

var parent = selection.parent;

if (parent.constructor.name != "Cell") {

    parent = selection.parentStory;

}

And if constructor does == cell, then you have to climb up the parent tree (or not, depending on what you're trying to get done).

Maybe that will help. Also perhaps helpful, below is a function I wrote to test if a selection is text or not. Here you can see the list of constructor names you might encounter. Perhaps not an answer to your question but hopefully guide you in the right direction.

function selectionIsText(selection) {

    switch (selection.constructor.name) {

        case "Character":

        case "Word":

        case "TextStyleRange":

        case "Line":

        case "Paragraph":

        case "TextColumn":

        case "Text":

        case "Cell":

        case "Column":

        case "Row":

        case "Table":

            return true;

    }

    return false;

}

William Campbell
KalsAuthor
Inspiring
April 2, 2019

Thanks for these ideas William.

williamc3112933  wrote

Not that it's simple, but one way to get there is to climb up the parent tree checking for the constructor name until you find "Story".

The problem is, you can go all the way up the tree and never see Story at all. If I select a cell and loop through consecutive parents (being careful to avoid an infinite loop, since the Application seems to think that it is its own parent!), I get this:

Cell

Table

TextFrame

Spread

Document

Application

As you can see, TextFrame is the parent of Table, not Story. According to the docs, the parent of a Table could be Story, along with a dozen other possibilities, but in my testing it is not. That's another thing I don't understand about the parent–child relationship—it seems so random. Thankfully, someone at Adobe thought to give us a parentStory property for text. Why not for tables and cells too? Who knows.

So anyway, at this stage I guess I need to loop through, check for Table, then use my old friend `storyOffset.parentStory` on the Table. I just thought there must be a more sensible way, but I'm slowly learning that Adobe's API is anything but sensible at times.

williamc3112933  wrote

Also perhaps helpful, below is a function I wrote to test if a selection is text or not. Here you can see the list of constructor names you might encounter. Perhaps not an answer to your question but hopefully guide you in the right direction.

Ah yes, that looks very much like some code out of Adobe's JavaScript Scripting Guide (under 'Working with text selections') which I actually used myself in an earlier version of my script. I've since changed it to just:

if (app.selection[0].hasOwnProperty("findGrep")) { … }

Since the findGrep() method is what I actually want to call on the text, this is perfect for filtering out invalid sections, and satisfyingly concise. :-) (Unlike the code I'm going to have to write to find the parent story in all possible circumstances!)

willcampbell7
Legend
April 2, 2019

When you get to TextFrame, that has the property parentStory. Yes weird that it doesn't show up in the parent chain above TextFrame (seems it should), but getting parentStory from the frame should be what you're looking for. If it will work for what you're hoping to do I couldn't say, but it's worth a try.

William Campbell