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

I'm completely confused by "app.documents[0].selection"and "app.activeDocument.selection[0]"

Guide ,
Sep 04, 2025 Sep 04, 2025
When I select a text box, both of the following are correct:
var sel = app.documents[0].selection;
alert(sel); // [object TextFrame]
alert(sel.length) // 1​


When my cursor is inside the text, I tried the code below and found both are [object TextFrame], but sel.length is invalid..
It should be noted that sel is undefined.

    item = app.activeDocument.selection[0];
    if (item.parent.textFrames[0].constructor.name == "TextFrame") {
        var sel = item.parent.textFrames[0];
    }
    alert(sel);//[object TextFrame]
    alert(sel.length)//undefined?????
TOPICS
How to , Scripting
246
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

correct answers 2 Correct answers

Community Expert , Sep 04, 2025 Sep 04, 2025

@dublove yes definitely. That is the way I would code it. I had a quick search and I have already written a function (for you, back in 2022!). Here is an example usage:

/**
 * @author m1b
 */
function main() {

    var doc = app.activeDocument;
    var sel = getTextFrames(doc.selection);

    alert('sel = ' + sel + ' (length: ' + sel.length + ')');

};
app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, 'Test');

/**
 * Returns any text frames found in given `items`
...
Translate
Community Expert , Sep 05, 2025 Sep 05, 2025

@dublove I wrote this function for getting the table. Not sure how good it is.

- Mark

 

function main() {

    var doc = app.activeDocument;
    var table = getTable(doc.selection);

    alert(table);

};
app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, 'Test');

/**
 * Attempts to return a Table, given an object.
 * @author m1b
 * @version 2023-02-06
 * @param {InsertionPoint|Text|Cells|Table|TextFrame} obj - an object related to a Cell.
 * @returns {Cell}
 */
f
...
Translate
Community Expert ,
Sep 04, 2025 Sep 04, 2025

@dublove there's usually no difference between app.activeDocument and app.documents[0].

 

Your problem is simply that sometimes the line

var sel = item.parent.textFrames[0];

doesn't get called, due to the predicate, so it will throw an error.

 

If you want to handle the error gracefully, do it like this:

var item = app.activeDocument.selection[0];

// must define sel outside the if/else
var sel;

if (item.parent.textFrames[0].constructor.name == "TextFrame") {
    sel = item.parent.textFrames[0];
}
else {
    sel = { length: 0 };
}

alert(sel);
alert(sel.length);
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
Guide ,
Sep 04, 2025 Sep 04, 2025

Hi m1b.

As you mentioned, is the value of sel.length 0?
But sel is already an object [object TextFrame].
If that's the case, my sort(a,b) interaction below won't capture the objects and will throw an error.

Actually, I just want to automatically obtain the final TextFrame based on different selections.

 alert(item.constructor.name);
    var sel;
    item = app.activeDocument.selection[0];
    if (item.parent.textFrames[0].constructor.name == "TextFrame") {
        sel = item.parent.textFrames[0];
    }
    else if (
        item.constructor.name == "Image"
        || item.constructor.name == "TextFrame") {
        sel = app.documents[0].selection;
    }
        sel.sort(function (a, b) {
        var aBounds = a.visibleBounds;
        var bBounds = b.visibleBounds;
 
        if (aBounds[1] < bBounds[1]) {
            return -1;
        } else if (aBounds[1] > bBounds[1]) {
            return 1;
        }
        else {
            return bBounds[0] - aBounds[0];
        }
    });
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
New Here ,
Sep 04, 2025 Sep 04, 2025

Really helpful breakdown — I’ve run into similar issues where features behave differently depending on device or context. It reminds me how important it is to double-check workflows across platforms, whether it’s Excel or even how a website displays on mobile vs desktop. Consistency really makes or breaks productivity.

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
Community Expert ,
Sep 04, 2025 Sep 04, 2025

@m1b said: "there's usually no difference between app.activeDocument and app.documents[0]."

 

Hi @dublove ,

the difference between app.documents[0] and app.activeDocument is a subtle one.

It could be that the addressed document with app.documents[0] is a document without a layout window.

Not so with app.activeDocument. That is always one with a layout window.

 

Let's proof that; start InDesign with no document open and add two documents with a different parameter for showingWindow in method add():

// START InDesign WITH NO OPEN DOCUMENT:
// Add two documents:
var doc1 = app.documents.add(); // showingWindow parameter true is default
var doc2 = app.documents.add( false ); // showingWindow parameter set to false

alert( app.documents.length ) ; // returns 2

alert( app.activeDocument == doc1 ); // returns true

 

Regards,
Uwe Laubender
( Adobe Community Expert )

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
Guide ,
Sep 04, 2025 Sep 04, 2025

@Laubender 

Too deep.
Can't grasp it all at once.
How do I make `sel = item.parent.textFrames[0];` into a real, controllable object?

It should be controllable like `sel = app.documents[0].selection;`.

 

I tried using
alert(app.documents[0].selection.parent);
but app.documents[0].selection doesn't seem to support parent.

 

It seems like alert(app.documents[0].selection[0].parent.textFrames[0]);
But sel.app.documents[0].selection[0].parent.textFrames[0];
still cannot be recognized as a real textFrame.
It remains a fake (logical textFrame?)

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
Guide ,
Sep 04, 2025 Sep 04, 2025

Hi @m1b @Laubender 

In other words, the textFrame obtained through conversion is not a true selection object.
It is not a collection and does not have a length property.
Does it need to be converted into a collection?

sel = [item.parent.textFrames[0]];
 

This time sort(a,b) didn't trigger an alert.

But the subsequent alert(“A:” + sel[0].parentPage) is invalid.

 

@m1b Is it possible to have something similar to the image?
As long as the cursor is within the text box, always return the textFrame object.

 

    var doc = app.activeDocument,
        items = doc.selection;
var graphics = getGraphics(doc.selection);
function getGraphics(items) {
    var graphics = [];
    if ('Array' === items.constructor.name) {
        for (var i = 0; i < items.length; i++)
            graphics = graphics.concat(getGraphics(items[i]));
    }

    else if (
        items.hasOwnProperty('allGraphics')
        && items.allGraphics.length > 0
    )
        graphics = graphics.concat(items.allGraphics);
    else if (
        items.hasOwnProperty('allPageItems')
        && items.allPageItems.length > 0
    )
        graphics = graphics.concat(getGraphics(items.allGraphics));
    else if ('Image' === items.constructor.name) {
        graphics.push(items);
    }
    return graphics;
};

 

 

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
Community Expert ,
Sep 04, 2025 Sep 04, 2025

@dublove yes definitely. That is the way I would code it. I had a quick search and I have already written a function (for you, back in 2022!). Here is an example usage:

/**
 * @author m1b
 */
function main() {

    var doc = app.activeDocument;
    var sel = getTextFrames(doc.selection);

    alert('sel = ' + sel + ' (length: ' + sel.length + ')');

};
app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, 'Test');

/**
 * Returns any text frames found in given `items`.
 * @author m1b
 * @version 2025-09-05
 * @param {DOM item} items - a DOM item or items to search in, eg. doc.selection.
 * @returns {Array<TextFrame>}
 */
function getTextFrames(items) {

    if (undefined == items)
        return [];

    var parentTextFrame;
    var found = [];

    if (!items.hasOwnProperty('0'))
        items = [items];

    for (var i = 0, item; i < items.length; i++) {

        item = items[i];

        if ('TextFrame' === item.constructor.name)
            found.push(item);

        else if (
            // item contains textFrames
            item.hasOwnProperty('textFrames')
            && item.textFrames.length > 0
        )
            found = found.concat(getTextFrames(item.textFrames));


        else if (
            // is contained by textFrame(s)
            item.hasOwnProperty('parentTextFrames')
            && item.parentTextFrames.length > 0
        )
            found = found.concat(getTextFrames(item.parentTextFrames));


        else if (
            // is in a story, which may contain textFrames
            item.hasOwnProperty('parentStory')
        )
            found = found.concat(getTextFrames([item.parentStory]));


        // has a parent which might be a textFrame
        else if (item.hasOwnProperty('parent')) {

            var parent = item.parent;

            while (
                'Document' !== parent.constructor.name
                && !parentTextFrame
            ) {
                parentTextFrame = item.parent;

                if ('TextFrame' === parent.constructor.name) {
                    parentTextFrame = item.parent;

                }

            }

        }

        if (
            parentTextFrame
            && 'TextFrame' === parentTextFrame.constructor.name
        )
            // store the parent text frame
            found.push(parentTextFrame);

        else if (
            // contains page items, which may be textFrames
            item.hasOwnProperty('pageItems')
            && item.pageItems.length > 0
        )
            found = found.concat(getTextFrames(item.pageItems));

    }

    return found;

};

Edit 2025-09-05: fixed bug in getTextFrames function that caused stack overrun.

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
Guide ,
Sep 04, 2025 Sep 04, 2025

Hi m1b.

You're incredibly formidable, far ahead of your time.
Back in 2022, I didn't even have the capacity to recognize this issue existed.

 

 

This is perfect. The problem is solved in an instant.

Thank you very much.

 

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
Guide ,
Sep 04, 2025 Sep 04, 2025

Hi @m1b 

Is there a table version?
Whether you select text within a cell, select a cell, or select a table, it always returns "Table".
When the cursor is inside a table, I don't want to get textFrame.

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
Community Expert ,
Sep 05, 2025 Sep 05, 2025

@dublove I wrote this function for getting the table. Not sure how good it is.

- Mark

 

function main() {

    var doc = app.activeDocument;
    var table = getTable(doc.selection);

    alert(table);

};
app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, 'Test');

/**
 * Attempts to return a Table, given an object.
 * @author m1b
 * @version 2023-02-06
 * @param {InsertionPoint|Text|Cells|Table|TextFrame} obj - an object related to a Cell.
 * @returns {Cell}
 */
function getTable(obj) {

    if (obj == undefined)
        return;

    if ('Array' === obj.constructor.name) {
        for (var i = 0, table; i < obj.length; i++) {
            table = getTable(obj[i]);
            if (table && table.isValid)
                return table;
        }
        return;
    }

    if (obj.constructor.name == 'Cell')
        return obj.parent;

    if (obj.parent.constructor.name == 'Cell')
        return obj.parent.parent;

    if (
        obj.hasOwnProperty('cells')
        && obj.cells.length > 0
    )
        return obj.cells[0].parent;

    if (
        obj.hasOwnProperty('tables')
        && 0 !== obj.tables.length
    )
        return obj.tables[0];

};
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
Guide ,
Sep 05, 2025 Sep 05, 2025

@m1b 

There's an issue:

If I currently have an image selected,

getTextFrames(doc.selection) does not return null.    Instead, it incorrectly displays my entire script code.


getGraphics(doc.selection) does not seem to have this issue. Even if I select text, it returns null(Nothing unusual occurred.).

 

In other words, if getTextFrames() fails to retrieve results, it will throw an error.

 

var doc = app.activeDocument;
var items = doc.selection;
var grs = getGraphics(doc.selection);
var tfs = getTextFrames(doc.selection);

 

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
Community Expert ,
Sep 05, 2025 Sep 05, 2025

Thanks @dublove, I have corrected the bug in my getTextFrames function.

- Mark

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
Guide ,
Sep 05, 2025 Sep 05, 2025

Hi m1b.

Thank you very much.

 

This morning I used `graphics.length > 0 for the check.
Now ,haver replaced TextFrames, no exceptions.

 

Can TextFrames be divided into two scenarios:
A: Cursor inside the table.
B: Cursor outside the table.

 

Because sometimes when the cursor is inside the table, I don't want the text box to be affected.
Alternatively, it can be distinguished like this:

if(getTextFrames && !table) {
}

 

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
Guide ,
Sep 05, 2025 Sep 05, 2025

Hi @m1b 

If a text box is selected, it contains two tables.
getTable(doc.selection); only returns one table.

Is it possible to restrict the return to all tables within the text box, or all tables in the Story?

 

Additionally, when the cursor is within a cell, `getTable(doc.selection)` is not a collection and does not have a length property.

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
Guide ,
Sep 07, 2025 Sep 07, 2025
LATEST

Hi @m1b 

Found a minor bug:
When  cells are selected, 'getTextFrames' does not retrieve the textFrame.

0061.png

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