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

Script for Assigning Paragraph Styles to text with similar settings

Community Beginner ,
Jul 25, 2024 Jul 25, 2024

I'm looking for a script or some way to easily assign different paragraph styles to hundreds of text boxes inside a document all based on the format of the text. All of the text is identical in format, but on different pages. Obviously, I could just go and create styles based on the first page's text and then go and assign it on each subsequent page, but that is hundreds of pages and I'd like to avoid that if I can. 

 

The backstory: I have a designer who reports to me that is unfamiliar with Paragraph styles, but they just completed a document that I would like to make more evergreen. They ran a data merge, but didn't assign any styles prior to creating the merged document and then had hours of work afterwards adjusting graphics on each page. All of the text is the same and based on the initial text box, so is there a faster way than going through one by one to assign styles to all of the pages? That way, if anything needs changed moving foward we can easily adjust the style instead of having to adjust each page individually. 

 

Any help would be greatly appreciated — I'm new to using scripts and have no idea how to make them myself, but after using a few to speedup my workflow I figure it's worth asking before doing it all manually. 

TOPICS
How to , Scripting
1.3K
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 1 Correct answer

Community Expert , Jul 29, 2024 Jul 29, 2024

This would get all of the document’s text frames where the first word is "Compliments" then style the next 5 lines:

 

var doc = app.activeDocument;
var api = doc.allPageItems;

var tf;
for (var i = 0; i < api.length; i++){
    //gets all text frames where the first word of the frame is "Compliments"
    if (api[i].constructor.name  == "TextFrame" && api[i].paragraphs[0].words[0].contents == "Compliments") {
        tf = api[i]
        //Assigns Paragraph Styles named Name, Title, Email, Phone, 
...
Translate
Community Expert ,
Jul 25, 2024 Jul 25, 2024

Can you show us an exemple of the text frames? Maybe you don't need a script, but a simple (or GREP) find and replace could work.

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 Beginner ,
Jul 29, 2024 Jul 29, 2024

It's a single text frame per spread with the same basic information. 

 

When they did the merge it went as follows:

 

Rep's Name

Title

Email

Phone number

companyname.com

 

Each rep name woul need to be it's own style and then the info that follows could be one paragraph style — I would like some of the elements to be bolded but I know just enough GREP that I think I can easily create a character style and apply those. The format should be consistent on each page with maybe a few exceptions, but so long as I can do a majority automatically I wouldn't mind doing some manual formatting. 

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 ,
Jul 29, 2024 Jul 29, 2024

This would get all of the document’s text frames where the first word is "Compliments" then style the next 5 lines:

 

var doc = app.activeDocument;
var api = doc.allPageItems;

var tf;
for (var i = 0; i < api.length; i++){
    //gets all text frames where the first word of the frame is "Compliments"
    if (api[i].constructor.name  == "TextFrame" && api[i].paragraphs[0].words[0].contents == "Compliments") {
        tf = api[i]
        //Assigns Paragraph Styles named Name, Title, Email, Phone, and Company to lines 2 thru 6
        tf.paragraphs[1].appliedParagraphStyle = makeParaStyle(doc, "Name")
        tf.paragraphs[2].appliedParagraphStyle = makeParaStyle(doc, "Title")
        tf.paragraphs[3].appliedParagraphStyle = makeParaStyle(doc, "Email")
        tf.paragraphs[4].appliedParagraphStyle = makeParaStyle(doc, "Phone")
        tf.paragraphs[5].appliedParagraphStyle = makeParaStyle(doc, "Company")
    } 
};   


/**
* Makes a new named ParagraphStyle if it does not already exist 
* @ param the document to add the style to 
* @ param style name 
* @ return the new paragraph style 
*/

function makeParaStyle(d, n){
    if (d.paragraphStyles.itemByName(n).isValid) {
        return d.paragraphStyles.itemByName(n);
    } else {
        return d.paragraphStyles.add({name:n});
    }
}

 

 

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 Beginner ,
Jul 30, 2024 Jul 30, 2024

Hi Rob!

Thank you so much for this script, it worked well for the specific document. I ended up playing around with ChatGPT and through many trials and errors I created a script that allows you to specify a font, style and size to apply a paragraph style throughout an entire document. I have 0 scripting experience so I can't say this code is as clean and simple as it should be, but it is exactly what I was looking for and I figured I should share it!


 

 

#target indesign

function applyParagraphStyleToAllText() {
    var doc = app.activeDocument;

    // Create a dialog window
    var dlg = new Window('dialog', 'Apply Paragraph Style to All Text');

    // Paragraph Style Listbox
    dlg.add('statictext', undefined, 'Select Paragraph Style:');
    var paragraphStyleListbox = dlg.add('listbox', [0, 0, 200, 200], getAllParagraphStyles(doc));
    paragraphStyleListbox.selection = 0; // Default to the first style

    // Font Family Listbox
    dlg.add('statictext', undefined, 'Select Font Family:');
    var fontFamilyListbox = dlg.add('listbox', [0, 0, 200, 200], getAllFontFamilies());
    fontFamilyListbox.selection = 0; // Default to the first font family

    // Font Style Dropdown
    dlg.add('statictext', undefined, 'Select Font Style:');
    var fontStyleDropdown = dlg.add('dropdownlist', undefined, getFontStyles(fontFamilyListbox.selection.text));
    fontStyleDropdown.selection = 0; // Default to the first style

    // Update font styles when the font family changes
    fontFamilyListbox.onChange = function() {
        var selectedFontFamily = fontFamilyListbox.selection.text;
        fontStyleDropdown.removeAll();
        var styles = getFontStyles(selectedFontFamily);
        for (var i = 0; i < styles.length; i++) {
            fontStyleDropdown.add('item', styles[i]);
        }
        fontStyleDropdown.selection = 0;
    };

    // Font Size Input
    dlg.add('statictext', undefined, 'Enter Font Size:');
    var fontSizeInput = dlg.add('edittext', [0, 0, 100, 20], '12'); // Default size is 12

    // Add buttons
    var btnGroup = dlg.add('group');
    btnGroup.add('button', undefined, 'Apply', {name: 'ok'});
    btnGroup.add('button', undefined, 'Cancel', {name: 'cancel'});

    // Show the dialog
    var dlgResult = dlg.show();

    // Handle dialog response
    if (dlgResult === 1) { // 1 indicates 'ok' was clicked
        var selectedParagraphStyleName = paragraphStyleListbox.selection.text;
        var selectedFontFamily = fontFamilyListbox.selection.text;
        var selectedFontStyle = fontStyleDropdown.selection.text;
        var enteredFontSize = parseFloat(fontSizeInput.text); // Read font size as a number

        $.writeln("Selected Paragraph Style: " + selectedParagraphStyleName); // Log selected style
        $.writeln("Selected Font Family: " + selectedFontFamily); // Log selected font family
        $.writeln("Selected Font Style: " + selectedFontStyle); // Log selected font style
        $.writeln("Entered Font Size: " + enteredFontSize); // Log entered font size

        if (isNaN(enteredFontSize) || enteredFontSize <= 0) {
            alert("Please enter a valid font size.");
            return;
        }

        var paragraphStyle;

        try {
            paragraphStyle = findParagraphStyleByName(doc, selectedParagraphStyleName);
            if (!paragraphStyle.isValid) {
                throw new Error("The selected paragraph style does not exist.");
            }
        } catch (e) {
            alert("Error: " + e.message);
            return;
        }

        var textFrames = doc.textFrames.everyItem().getElements();
        $.writeln("Number of text frames: " + textFrames.length); // Log number of text frames
        var appliedCount = 0;

        for (var i = 0; i < textFrames.length; i++) {
            var textFrame = textFrames[i];
            var paragraphs = textFrame.paragraphs.everyItem().getElements();
            $.writeln("Text Frame " + i + " contains " + paragraphs.length + " paragraphs."); // Log paragraphs in each text frame

            for (var j = 0; j < paragraphs.length; j++) {
                var paragraph = paragraphs[j];
                
                // Check if the paragraph has the specified character format
                var characters = paragraph.characters.everyItem().getElements();
                for (var k = 0; k < characters.length; k++) {
                    var character = characters[k];
                    if (character.appliedFont.fontFamily === selectedFontFamily && character.appliedFont.fontStyleName === selectedFontStyle && character.pointSize == enteredFontSize) {
                        $.writeln("Applying style to paragraph with contents: " + paragraph.contents); // Log paragraph contents
                        paragraph.appliedParagraphStyle = paragraphStyle;
                        appliedCount++;
                        break;
                    }
                }
            }
        }

        alert("Applied paragraph style to " + appliedCount + " paragraphs.");
    }
}

function getAllParagraphStyles(doc) {
    var paragraphStyles = [];

    function addStyles(styles) {
        for (var i = 0; i < styles.length; i++) {
            var style = styles[i];
            if (style.name !== "[Basic Paragraph]") { // Exclude the default style if desired
                paragraphStyles.push(style.name);
            }
        }
    }

    function addStylesFromGroups(groups) {
        for (var j = 0; j < groups.length; j++) {
            var group = groups[j];
            addStyles(group.paragraphStyles);
            addStylesFromGroups(group.paragraphStyleGroups);
        }
    }

    addStyles(doc.paragraphStyles);
    addStylesFromGroups(doc.paragraphStyleGroups);

    return paragraphStyles;
}

function findParagraphStyleByName(doc, name) {
    var styles = doc.paragraphStyles;
    var groups = doc.paragraphStyleGroups;

    function searchStyles(styles) {
        for (var i = 0; i < styles.length; i++) {
            if (styles[i].name === name) {
                return styles[i];
            }
        }
        return null;
    }

    function searchGroups(groups) {
        for (var j = 0; j < groups.length; j++) {
            var group = groups[j];
            var style = searchStyles(group.paragraphStyles);
            if (style) {
                return style;
            }
            style = searchGroups(group.paragraphStyleGroups);
            if (style) {
                return style;
            }
        }
        return null;
    }

    var style = searchStyles(styles);
    if (style) {
        return style;
    }
    return searchGroups(groups);
}

function getAllFontFamilies() {
    var fontFamilies = [];
    var fontFamilyMap = {}; // Use an object to track unique font families
    var fonts = app.fonts.everyItem().getElements();

    for (var i = 0; i < fonts.length; i++) {
        var fontFamily = fonts[i].fontFamily;

        // Debugging: Check if fontFamily is a string
        if (typeof fontFamily !== 'string') {
            alert("fontFamily is not a string. Value: " + fontFamily);
            continue; // Skip this iteration
        }

        // Use the object to track if the font family has already been added
        if (!fontFamilyMap[fontFamily]) {
            fontFamilyMap[fontFamily] = true; // Mark this font family as added
            fontFamilies.push(fontFamily);
        }
    }

    return fontFamilies;
}


function getFontStyles(fontFamily) {
    var fontStyles = [];
    var fonts = app.fonts.everyItem().getElements();

    for (var i = 0; i < fonts.length; i++) {
        if (fonts[i].fontFamily === fontFamily) {
            fontStyles.push(fonts[i].fontStyleName);
        }
    }

    return fontStyles;
}

function getFontSizes() {
    var fontSizes = [];
    for (var i = 6; i <= 72; i++) { // Common font sizes from 6 to 72
        fontSizes.push(i.toString());
    }
    return fontSizes;
}

applyParagraphStyleToAllText();

 

 

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 ,
Jul 30, 2024 Jul 30, 2024

@Zach Field

 

This part:

 

        var textFrames = doc.textFrames.everyItem().getElements();
        $.writeln("Number of text frames: " + textFrames.length); // Log number of text frames
        var appliedCount = 0;

        for (var i = 0; i < textFrames.length; i++) {
            var textFrame = textFrames[i];
            var paragraphs = textFrame.paragraphs.everyItem().getElements();
...
} ;

 

 

should be done differently - if you want to process all texts in the document - you should iterate through doc.stories collection.

 

In InDesign's scripting DOM, TextFrame can't exist on its own - it's always associated with a Story - and Story always have at least one TextFrame. 

 

If you have a Document with only single TextFrame Stories - no big deal - but if you'll have multi TextFrame Stories - you might end up with processing same paragraphs twice - when they split between TextFrames. No big deal - just waste of time. 

 

So, it's a good practice to rather process Stories instead of TextFrames. 

 

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 Beginner ,
Jul 31, 2024 Jul 31, 2024

@Robert at ID-Tasker That's really good information to know — like I mentioned before, I have no knowledge of coding. To make this code I had to start from a very simple idea and add complexity with each step all while troubleshooting each new code. Without knowing the underlying mechanics of how InDesign works it's impossible to know why something is breaking and the AI seems to have a hard time making the most optimal choices. An example would be creating the scrollable menu for Paragraph styles: The first iteration only included styles that weren't grouped. Troubleshooting that alone was at least an hour of constant back and forths so hopefully as I continue my learning I can start understanding why something may be failing. 

 

I appreciate your help and any additional resources you could recommned would be greatly appreciated as I being my journey into scripting!

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 ,
Jul 31, 2024 Jul 31, 2024
LATEST

@Zach Field

 

You are welcome.

 

I would rather suggest that you stop wasting your time on using AI - and just post questions here. 

 

Here is something that should help you a bit:

https://abg.ee/wp-content/uploads/2019/10/Adobe-Intro-To-Scripting.pdf 

 

Then:

https://www.indesignjs.de/extendscriptAPI/indesign-latest/

 

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 ,
Jul 25, 2024 Jul 25, 2024

Hi @Zach Field , Just to clarify, do all of the pages have the same number of text frames, and each text frame on page 1 is styled differently?

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 Beginner ,
Jul 29, 2024 Jul 29, 2024

The original template that we used to generate the merge had one text frame. 

 

It was formatted like this:

 

Rep's Name

Title

Email

Phone number

companyname.com

 

The rep's name was stylized differently, but the remaining text was formatted the same and each has a paragraph break.

 

If it weren't for the edits and deadline , I would have them redo the merge with the proper styles. I may just need to redo the document, but if there was a way to apply styles using a script it would help me with this and other documents. Until I joined the team, no one used styles properly.Most documents were created by duplicating pages and formatting each copy block individually. 

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 ,
Jul 29, 2024 Jul 29, 2024

@Zach Field

 

If you work on a PC - it would be a breeze with my ID-Tasker - not free, but I can give you access to the full version for a few days. 

 

You could process only specific pages, layers, locations, etc. And you can easily change number of paragraphs to be styled and their order. 

 

And you can of course process unlimited number of files automatically - even overnight. 

 

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