Skip to main content
Participant
May 10, 2025
Answered

Change found text to anchored textFrame

  • May 10, 2025
  • 2 replies
  • 398 views

Hi,

I'm trying to find text with specific character style and create a new anchored TextFrame.

The code below works only on first match.

 var main = function() {
    var doc = app.properties.activeDocument, found, foundlength, selection = app.selection[0]
    if ( !doc ) return;
    app.findGrepPreferences = null;
    app.findGrepPreferences.properties = {
	findWhat : ".+",
     appliedCharacterStyle : "style1"
    };
    found = selection.findGrep();
	foundlength = found.length
    if ( !found.length ) {
        alert("Nothing found");
        return;
    }
 for (i = 0; i<foundlength; i++) {
        var myNewTextFrame = found[i].insertionPoints[0].textFrames.add();

       //myNewTextFrame.appliedObjectStyle = objectStyle;
        found[i].move(LocationOptions.AT_BEGINNING, myNewTextFrame.insertionPoints[0]);
 }
  }
  app.doScript(String(main()),ScriptLanguage.JAVASCRIPT,[],UndoModes.ENTIRE_SCRIPT,'main');
Correct answer m1b

Hi @lucignolo25859033u0ra you are very close! The main problem is that when you go through the loop

for (i = 0; i < foundlength; i++) {

you are going forwards, starting with the first found text, and going onwards. The problem is that you are also changing the text by moving it, which means that every found reference thereafter is broken (see note afterwards).

 

So go through the loop backwards, then it doesn't matter if the references are broken. Change to this line:

for (var i = found.length - 1; i >= 0; i--) {

- Mark

 

 

Note on why references get broken: here is a typical specifier of some found text:

(/document[@id=8]//story[@id=222]/character[1249] to /document[@id=8]//story[@id=222]/character[1257])

See those character[1249]  to ... character[1257]? Well if you remove some earlier characters from the story, those numbers will be wrong, and very often become invalid.

2 replies

m1b
Community Expert
Community Expert
May 10, 2025

While I think of it, I just yesterday wrote a function along these same lines for my own script. Maybe you can get some ideas from it, or incorporate the function into your script. Here it is, just a demo of the convertToAnchoredText function:

/**
 *  Convert To Anchored Text.js
 *
 *  m1b
 *  2025-05-10
 */
function main() {

    var doc = app.activeDocument,
        text = doc.selection[0];

    if (!text)
        return alert('Please select some text and try again.');

    var frame = convertToAnchoredText(doc, doc.selection[0]);

    // do something with the anchored frame ...

};
app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, 'Convert Text To Anchored Text');

/**
 * Converts text into anchored text frame
 * without moving the text visually.
 *  m1b
 *  2025-05-10
 *  {Document} doc = an Indesign Document.
 *  {Text} text - an Indesign text object.
 *  {TextFrame} - the anchored text frame.
 */
function convertToAnchoredText(doc, text) {

    if (!text || !text.hasOwnProperty('baseline'))
        throw new Error('convertToAnchoredText: bad `text` supplied.');

    var ip = text.parentStory.insertionPoints[text.index],
        frame = doc.textFrames.add({ geometricBounds: [0, 0, 5000, 5000] });

    text.duplicate(LocationOptions.AFTER, frame.texts[0].insertionPoints[0]);
    text.remove();

    frame.fit(FitOptions.FRAME_TO_CONTENT);

    frame.anchoredObjectSettings.insertAnchoredObject(ip, AnchorPosition.ANCHORED);

    frame.anchoredObjectSettings.properties = {
        anchorPoint: AnchorPoint.BOTTOM_RIGHT_ANCHOR,
        anchorSpaceAbove: 0,
        anchorXoffset: 0,
        anchorYoffset: 0,
        anchoredPosition: AnchorPosition.INLINE_POSITION,
        horizontalAlignment: HorizontalAlignment.LEFT_ALIGN,
        horizontalReferencePoint: AnchoredRelativeTo.TEXT_FRAME,
        lockPosition: false,
        pinPosition: true,
        spineRelative: false,
        verticalAlignment: VerticalAlignment.BOTTOM_ALIGN,
        verticalReferencePoint: VerticallyRelativeTo.LINE_BASELINE,
    };

    return frame;

};

Edit 2025-05-11: changed bounds calculation (which failed on some composers, eg. Japanese) to use Indesign's fit frame to content, as per @Robert at ID-Tasker's excellent suggestion.

Robert at ID-Tasker
Legend
May 10, 2025

@m1b 

 

Instead of checking each character - check first & last in the TextLine(s) - will be WAY quicker. 

 

Also, you're not checking if they're in the same TextFrame or on the same Page / Spread. 

 

m1b
Community Expert
Community Expert
May 10, 2025

> Instead of checking each character - check first & last in the TextLine(s) - will be WAY quicker.

 

Sure quicker, but I'm not confident that that will accurately read the bounds of every permutation of baseline-shifting and different sized characters. Anyway it's plenty fast enough for my purposes so far—it's only reading properties, not altering the DOM, so no reason it should be noticeably slow.

 

> Also, you're not checking if they're in the same TextFrame or on the same Page / Spread.

 

Good spotting! I didn't even think of that. Maybe I will set the text to no-break to ensure that the text was in a block and not split.

 

In any case it is a quick first draft and there are many problems with it—it doesn't even get the bounds right in every case yet. I'll work on it again when I get the chance.

- Mark

m1b
Community Expert
m1bCommunity ExpertCorrect answer
Community Expert
May 10, 2025

Hi @lucignolo25859033u0ra you are very close! The main problem is that when you go through the loop

for (i = 0; i < foundlength; i++) {

you are going forwards, starting with the first found text, and going onwards. The problem is that you are also changing the text by moving it, which means that every found reference thereafter is broken (see note afterwards).

 

So go through the loop backwards, then it doesn't matter if the references are broken. Change to this line:

for (var i = found.length - 1; i >= 0; i--) {

- Mark

 

 

Note on why references get broken: here is a typical specifier of some found text:

(/document[@id=8]//story[@id=222]/character[1249] to /document[@id=8]//story[@id=222]/character[1257])

See those character[1249]  to ... character[1257]? Well if you remove some earlier characters from the story, those numbers will be wrong, and very often become invalid.