Copy link to clipboard
Copied
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?????
@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`
...
@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
...
Copy link to clipboard
Copied
@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);
Copy link to clipboard
Copied
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];
}
});
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
@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 )
Copy link to clipboard
Copied
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?)
Copy link to clipboard
Copied
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?
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;
};
Copy link to clipboard
Copied
@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.
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
@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];
};
Copy link to clipboard
Copied
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);
Copy link to clipboard
Copied
Thanks @dublove, I have corrected the bug in my getTextFrames function.
- Mark
Copy link to clipboard
Copied
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) {
}
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
Find more inspiration, events, and resources on the new Adobe Community
Explore Now