Skip to main content
Bedazzled532
Inspiring
October 2, 2024
Answered

How to Anchor a Text Frame to a Specific Character Style in InDesign Scripting

  • October 2, 2024
  • 1 reply
  • 1190 views

Hi

I have a requirement to anchor a text frame with numbers in it to a text where a particular character style is applied.  The text frame which needs to be anchored has a paragraph style and an object style applied to it.

 

I have attached a screenshot and and IDML file also.

 

Here is the code:

 

//First copy the text frame with object style applied to it.
//This frame will be anchored at the word/sentence with a particular character style

// Get the active document
var doc = app.activeDocument;

//Get the object style
var objectStyle = doc.objectStyles.itemByName("boxedObject");

//Change object style setting
objectStyle.anchoredObjectSettings.anchoredPosition = AnchorPosition.ANCHORED;
objectStyle.anchoredObjectSettings.anchorPoint = AnchorPoint.TOP_LEFT_ANCHOR;
objectStyle.anchoredObjectSettings.horizontalReferencePoint = AnchoredRelativeTo.ANCHOR_LOCATION;


//Reset findchange grep preferences
app.findGrepPreferences = app.changeGrepPreferences = null;

//find one or more words separated by a space
app.findGrepPreferences.findWhat="\\w+(?:\\s\\w+)*";

//Filter the search for a particular character style
app.findGrepPreferences.appliedCharacterStyle = "boxedul";

//Paste the copied textframe back
app.changeGrepPreferences.changeTo="~c$0";

//Execute the find change
var found = doc.changeGrep();

 

 

All is working fine except that I am unable to change the width of the anchored textframe as per the width of the text where a particular character style is appiled. I believe the screenshot attached will make my question more clear .

 

I am unable to write that last part of the code. It seems be way above my knowlege.

Thanks

 

 

<Title renamed by MOD>

This topic has been closed for replies.
Correct answer m1b

@m1b Thank you so much. It because of this group and people like you that I have come this far in scripting.

 

I still face lot of issues while scripting but gradually picking up.

 

I wanted to to make this script work for only the selected text. Looking for what options do I have in this kind of situation.

 

I have kept your script as a final copy. It actually is great because a single Ctrl Z takes care of undo of the entire script.

 

Thanks once again @m1b 


I am pleased it was helpful. Yes I like to put my Indesign scripts through the `doScript` method which consolidates the actions into a single Undo.

 

I've adjusted the script to work with either selected text frames, or selected text or, if nothing is selected, then the whole document. I hope you can see how I did it here:

/**
 * @File Add Numbered Boxes Below Text.js
 * @7111211 sharhidr100 and m1b
 * @discussion https://community.adobe.com/t5/indesign-discussions/how-to-anchor-a-text-frame-to-a-specific-character-style-in-indesign-scripting/m-p/14894001
 */
function main() {

    // Get the active document
    var doc = app.activeDocument,
        items = doc.selection;

    if (0 === items.length) {
        // whole document
        addNumberedTextBoxes(doc);
    }

    else {
        // selected items
        for (var i = 0; i < items.length; i++)
            addNumberedTextBoxes(doc, items[i]);
    }

};
app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, 'Make Numbered Boxes');

/**
 * Adds numbered boxes to text of `target`.
 * Removes existing numbered boxes first.
 * If no `target` is given, then perform
 * function on whole document `doc`.
 * @7111211 sharhidr100 and m1b
 * @version 2024-10-04
 * @9397041 {Document} doc - an Indesign Document.
 * @9397041 {TextFrame|Text} [target] - add numbered boxes to this object (default: doc).
 */
function addNumberedTextBoxes(doc, target) {

    const BOX_OBJECT_STYLE_NAME = 'boxedObject',
        UNDERLINE_CHARACTER_STYLE_NAME = 'boxedul';

    target = target || doc;

    if (
        undefined == target.findGrep
        || !target.hasOwnProperty('textFrames')
    )
        // Can't use this item
        return;

    // Remove existing boxes
    var found = (target.hasOwnProperty('stories'))
        ? target.stories.everyItem().textFrames.everyItem().getElements()
        : target.textFrames;

    for (var i = found.length - 1; i >= 0; i--)
        if (BOX_OBJECT_STYLE_NAME === found[i].appliedObjectStyle.name)
            found[i].remove();

    // Reset find grep preferences
    app.findGrepPreferences = NothingEnum.NOTHING;

    // Filter the search for a particular character style
    app.findGrepPreferences.appliedCharacterStyle = UNDERLINE_CHARACTER_STYLE_NAME;

    // Perform the find
    found = target.findGrep();

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

        // Add the box
        tf = found[i].insertionPoints[0].textFrames.add();
        tf.properties = {
            geometricBounds: [0, found[i].horizontalOffset, 2, found[i].endHorizontalOffset],
            appliedObjectStyle: doc.objectStyles.item(BOX_OBJECT_STYLE_NAME),
            contents: ' ',
        };

    }

};

1 reply

Bedazzled532
Inspiring
October 2, 2024

For some reason the last line doc.changeGrep() is not working properly I guess.

 

I added following lines at the last:

for(i=0;i<found.length;i++){
alert(found[i].horizontalOffset);
alert(found[i].endHorizontalOffset);
alert(found[i].contents);

 

It is not showing the whole matched text. Following text is printed after adding the lines:

"underli" and "pt whic"

It should match "underline selection" and "written". I dont know where "pt whic" came from. It does not have "boxedul" character style applied.

 

Bedazzled532
Inspiring
October 2, 2024

Ok. I have managed to achieve what I want. I just needs little fine-tuning.

 

Here is the updated code just in case if anyone needs it.

 

// Get the active document
var doc = app.activeDocument;

//Filter the search for a particular character style
app.findGrepPreferences.appliedCharacterStyle = "boxedul";

//Execute the find change
var found = doc.findGrep();

//Reset findchange grep preferences
app.findGrepPreferences = app.changeGrepPreferences = null;


for(i=found.length-1;i >=0;i--){
tf = found[i].insertionPoints[0].textFrames.add();
    tf.properties =
    {
      geometricBounds :[0,found[i].horizontalOffset,2,found[i].endHorizontalOffset],
      strokewidth: 0,
      fillColor : "None",
      appliedObjectStyle: doc.objectStyles.item("boxedObject")
    };
		
    tf.anchoredObjectSettings.properties = {
      anchoredPosition: AnchorPosition.ANCHORED,
      anchorPoint : AnchorPoint.TOP_LEFT_ANCHOR,
      verticalReferencePoint : AnchoredRelativeTo.ANCHOR_LOCATION
    };

}
m1b
Community Expert
Community Expert
October 4, 2024

Hi @Bedazzled532, you have done a marvelous job here. Your scripting skills are really improving!

 

For your learning, I have cleaned up your code a little bit (not too much!) and also included a slightly modified demo document (I moved some of the scripted properties into the Object Style).

- Mark

 

/**
 * @file Add Numbered Boxes Below Text.js
 * @author sharhidr100 (modified by m1b)
 * @discussion https://community.adobe.com/t5/indesign-discussions/how-to-anchor-a-text-frame-to-a-specific-character-style-in-indesign-scripting/m-p/14894001
 */
function main() {

    // Get the active document
    var doc = app.activeDocument;

    // Reset find grep preferences
    app.findGrepPreferences = NothingEnum.NOTHING;

    // Filter the search for a particular character style
    app.findGrepPreferences.appliedCharacterStyle = "boxedul";

    // Execute the find change
    var found = doc.findGrep();

    for (var i = found.length - 1, tf; i >= 0; i--) {
        tf = found[i].insertionPoints[0].textFrames.add();
        tf.properties = {
            geometricBounds: [0, found[i].horizontalOffset, 2, found[i].endHorizontalOffset],
            appliedObjectStyle: doc.objectStyles.item("boxedObject"),
            contents: ' ',
        };
    }

};
app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, 'Make Numbered Boxes');