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

Get unused text styles using Extendscript

Participant ,
Dec 28, 2022 Dec 28, 2022

Copy link to clipboard

Copied

I use Extendscript to help me review students' work in InDesign. I run a script (.jsx) that goes through a document and creates a report. The point is to avoid manual, tedious and error-prone work for about 5 InDesign files x 60 students per semester. The report already includes many things like page size, bleed, margins, parent page columns and application, text style options, baseline grid, etc. This script saves me a HUGE amount of time and makes it less likely that I'll forget to check for anything in particular.

 

What I cannot do yet is to include in this report wether or nor unused paragraph and character styles exist, preferably listing their names.

 

I tried:

  • Searching the documentation for a property that might indicate if the paragraph/character style is being used or not.

  • Invoking (.invoke() method) the Select All Unused menu action from the Paragraph Styles panel. I explored adding event listeners and looking for any results, and also checked the Panel javascript documentation for any way to access a selection. According to what little I found, this is not possible because there's nothing relative to a selection regarding UI elements.

 

I also considered looping through all stories and paragraphs, checking for the styles in use, and accounting for styles used inside other styles (like "based on"). I've yet to explore scripting with find/replace, because that option would not tell me wether a style with zero uses is the basis for another style. Also, I feel there should be a simpler alternative. Does anyone know of one?

TOPICS
Scripting

Views

950

Translate

Translate

Report

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 ,
Dec 28, 2022 Dec 28, 2022

Copy link to clipboard

Copied

Copy all text elements to a new document - only used styles will be copied 😉 

Based on, etc. - I'm pretty sure even the ones that are used in GREP rules for ParaStyle and from Cell / Para Style should be copied 😉 

 

▒► ID-Tasker / ID-Tasker Server - work smart not hard ◄▒

Votes

Translate

Translate

Report

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 ,
Dec 28, 2022 Dec 28, 2022

Copy link to clipboard

Copied

Hi @Robert Tkaczyk, nice bit of thinking outside the box! In this case I think it would be more complicated to implement however. - Mark

Votes

Translate

Translate

Report

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 ,
Dec 28, 2022 Dec 28, 2022

Copy link to clipboard

Copied

????

Looping through the Stories ?? Then comparing styles by names / checking which one from the old doc doesn't exist in the new doc ??

 

In the best case scenario - only two loops.

If styles are in Groups - recursion.

 

How can this be more complicated ??

 

▒► ID-Tasker / ID-Tasker Server - work smart not hard ◄▒

Votes

Translate

Translate

Report

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 ,
Dec 28, 2022 Dec 28, 2022

Copy link to clipboard

Copied

Perhaps you are right, and I can see your approach could have advantages.

 

But I gave it some thought before writing the script the way I did. Even what you describe sounds more complicated to me, despite that you don't mention creating a new document and duplicating everything across—all the DOM stuff that Brian's approach doesn't need.

 

As always I am keen to improve, so if you write up the script using your approach, that would be excellent—not just for me, but for anyone else reading this.

- Mark

Votes

Translate

Translate

Report

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 ,
Dec 28, 2022 Dec 28, 2022

Copy link to clipboard

Copied

AFK so untested and in VB and only first level of Para / Char Styles checked. 

 

 

 

 

 

Set myInDi = CreateObject("InDesign.application") 

Set mySrcDoc = myindi.activedocument
Set myDestDoc = myindi.documents.add

For a = 1 to mySrcDoc.stories.count
Myindi.activedocument = mySrcDoc 
Call myindi.Select(mySrcDoc.Stories.item(a).texts.item(1))
Call myindi.Copy
Myindi.activedocument = myDestDoc 
Call myindi.paste
Next

Myindi.activedocument = mySrcDoc 

For a = 1 to mySrcDoc.paragraphstyles.count
On error resume next
Set myPStyle = myDestDoc.paragraphstyles.item(mySrcDoc.paragraphstyles.item(a).name)
If err.number then 
ListPSUnused = ListPSUnused & mySrcDoc.paragraphstyles.item(a).name & vbcr
End if
On error goto 0
Next


For a = 1 to mySrcDoc.characterstyles.count
On error resume next
Set myCStyle = myDestDoc.characterstyles.item(mySrcDoc.characterstyles.item(a).name)
If err.number then 
ListCSUnused = ListCSUnused & mySrcDoc.characterstyles.item(a).name & vbcr
End if
On error goto 0
Next

Call msgbox(ListPSUnused) 
Call msgbox(ListCSUnused)

 

 

 

▒► ID-Tasker / ID-Tasker Server - work smart not hard ◄▒

Votes

Translate

Translate

Report

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 ,
Dec 28, 2022 Dec 28, 2022

Copy link to clipboard

Copied

Hi @Robert Tkaczyk, thanks for starting your script. I definitely see it is a good way, especially if OP wants every style in document (although you'd have to include all objects too to get object styles—quite possible to do). It still isn't my preferred way, due to the complications involving moving stuff around the DOM. And I would definitely try to avoid using copy and paste, for two reasons (1) some items can be very slow to copy and paste, and (2) because it destroys the user's clipboard. You can get around this fairly easily by using the duplicate method on the story, but you need to make a text frame in the temp document to put it in. All quite possible, but as I said, not my preferred way (so far—you may change my mind!).

Anyway, as I said before, it would be excellent if you would put forward your working code, preferably in ExtendScript, so people can actually use your approach. I think it is a good way as I also said.

- Mark

Votes

Translate

Translate

Report

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 ,
Dec 28, 2022 Dec 28, 2022

Copy link to clipboard

Copied

I think you meant "try not to avoid" 😉 and who cares about clipboard? 

 

Just got another genius idea 😉

How about duplicating all pages in one go? 😉 would solve ALL problems 😉 

 

And by ExtendScript you meant JavaScript? My code isn't VB6 so should perfectly fine run as VBS.

Unfortunately, I don't code in JavaScript. 

VB I can do in my head 😉 but JS not so much 😞

 

▒► ID-Tasker / ID-Tasker Server - work smart not hard ◄▒

Votes

Translate

Translate

Report

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 ,
Dec 28, 2022 Dec 28, 2022

Copy link to clipboard

Copied

Yes! duplicating pages would be quite simple. I think that might be a great solution. Good thinking!

Sorry, but I can't test your VB code, as I am on Mac. And thanks for typo: fixed.

- Mark

Votes

Translate

Translate

Report

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 ,
Dec 29, 2022 Dec 29, 2022

Copy link to clipboard

Copied

You are very good with JS so it shouldn't be a problem for you to re-write it from VB to JS? 

 

▒► ID-Tasker / ID-Tasker Server - work smart not hard ◄▒

Votes

Translate

Translate

Report

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 ,
Dec 28, 2022 Dec 28, 2022

Copy link to clipboard

Copied

You  could do a findText series through all styles and check the results' length. You can check each styles basedOn while you do. 

Votes

Translate

Translate

Report

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 ,
Dec 28, 2022 Dec 28, 2022

Copy link to clipboard

Copied

I think @brianp311's approach might be the most practical. I've written it up:

/**
 * Find Unused Paragraph and CharacterStyles.
 * @discussion https://community.adobe.com/t5/indesign-discussions/get-unused-text-styles-using-extendscript/m-p/13450555
 */
function main() {

    var doc = app.activeDocument;

    var unusedParagraphStyles = findUnusedStyles(doc, 'ParagraphStyle'),
        unusedCharacterStyles = findUnusedStyles(doc, 'CharacterStyle');

    // report to user:
    var report = ['Unused Styles'];

    if (unusedParagraphStyles.length == 0)
        report.push('(No unused paragraph styles.)');
    else
        for (var i = 0; i < unusedParagraphStyles.length; i++)
            report.push('Paragraph style: ' + unusedParagraphStyles[i].name);

    if (unusedCharacterStyles.length == 0)
        report.push('(No unused character styles.)');
    else
        for (var i = 0; i < unusedCharacterStyles.length; i++)
            report.push('Character style: ' + unusedCharacterStyles[i].name);

    alert(report.join('\n'));



    /**
     * Find unused styles.
     * Based on idea by brianp311.
     * @author m1b
     * @version 2022-12-29
     * @param {Document} doc - an Indesign Document.
     * @param {String} styleType - can be 'ParagraphStyle' or 'CharacterStyle'.
     * @returns {Array} - the unused styles.
     */
    function findUnusedStyles(doc, styleType) {

        // reset grep prefs
        app.findGrepPreferences = NothingEnum.NOTHING;
        app.changeGrepPreferences = NothingEnum.NOTHING;

        // grep options
        app.findChangeGrepOptions.includeFootnotes = true;
        app.findChangeGrepOptions.includeHiddenLayers = true;
        app.findChangeGrepOptions.includeLockedLayersForFind = true;
        app.findChangeGrepOptions.includeLockedStoriesForFind = true;
        app.findChangeGrepOptions.includeMasterPages = true;

        var usedStyleIDs = [],
            unusedStyles = [],
            appliedProperty,
            styles;

        if (styleType == 'ParagraphStyle') {
            appliedProperty = 'appliedParagraphStyle';
            styles = doc.allParagraphStyles;
        }

        else if (styleType == 'CharacterStyle') {
            appliedProperty = 'appliedCharacterStyle';
            styles = doc.allCharacterStyles;
        }

        else
            // don't know what to do with this styleType
            return;

        for (var i = 0; i < styles.length; i++) {

            var style = styles[i];

            if (ignoreThisStyle(style))
                continue;

            if (isUnused(doc, style)) {
                unusedStyles.push(style);
                continue;
            }

            usedStyleIDs = usedStyleIDs.concat(getStyleIdChain(style));

        }

        // now remove any styles that were the basis for used styles
        for (var i = unusedStyles.length - 1; i >= 0; i--)
            if (indexOf(unusedStyles[i].id, usedStyleIDs) != -1)
                unusedStyles.splice(i, 1);

        // return the unused styles
        return unusedStyles;


        /**
         * Returns true when we want to ignore the style.
         * Currently only works for ParagraphStyle and
         * CharacterStyle.
         * @param {ParagraphStyle|CharacterStyle} style
         * @returns {Boolean}
         */
        function ignoreThisStyle(style) {

            return (
                style == undefined
                || (
                    style.hasOwnProperty('styleUniqueId')
                    && style.styleUniqueId === '' // [No style]
                )
            );

        };

        /**
         * Returns array of style ids
         * including the chain of 'basedOn' ids.
         * @param {ParagraphStyle|CharacterStyle} style
         * returns {Array<Number>} - the ids in the chain.
         */
        function getStyleIdChain(style) {

            if (ignoreThisStyle(style.basedOn))
                return [];

            var ids = [style.id];

            if (
                style.hasOwnProperty('basedOn')
                && style.basedOn != undefined
            )
                ids = ids.concat(getStyleIdChain(style.basedOn));

            return ids;

        };


        /**
         * Has the style been used in document?
         * @param {Document} doc
         * @param {ParagraphStyle|CharacterStyle} style
         */
        function isUnused(doc, style) {

            // find criteria
            app.findGrepPreferences[appliedProperty] = style;

            return (doc.findGrep()).length === 0;

        };


        /**
         * Returns index of obj in arr.
         * Returns -1 if not found.
         * @param {any} obj
         * @param {Array} arr
         * @returns {Number}
         */
        function indexOf(obj, arr) {

            for (var i = 0; i < arr.length; i++)
                if (arr[i] == obj)
                    return i;

            return -1;
        
        };



    };



} // end main

app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, 'Find unused styles');

 

@maguskrool please give it a go and let me know how it works. I hope you can test it much more thoroughly than I did! note that it currently only works with ParagraphStyles and CharacterStyles. Incorporating CellStyles will require some quite different logic. ObjectStyles could be done with a variation on the function.

- Mark

Votes

Translate

Translate

Report

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 ,
Dec 28, 2022 Dec 28, 2022

Copy link to clipboard

Copied

I am joining the party late, however I have a real use case in one of my projects that involve finding used styles in an IDS environment. I had ended up with almost the same code that @m1b wrote(Mark did you read my mind somehow :)). However now with @Robert Tkaczyk idea I would want to investigate it and see if it is a faster process. In my scenario the speed was a big issue where in we started with trying to delete unused styles and that was way too slow then I shifted to just getting the list of used styles, that is pretty fast, but if copying over pages can do the trick then I would be interested to see how fast that would go.

-Manan

Votes

Translate

Translate

Report

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 ,
Dec 28, 2022 Dec 28, 2022

Copy link to clipboard

Copied

Hi @Manan Joshi haha, great minds think alike! I am also interested in @Robert Tkaczyk's idea which I think is genius. I was planning to write it but I might not get a chance until tomorrow. Feel free to do it yourself, or you can wait for me. It will be a fun example! Thanks everyone. - Mark

P.S. are you able to test the speed on my script? I'm curious about where the slow part is.

Votes

Translate

Translate

Report

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 ,
Dec 28, 2022 Dec 28, 2022

Copy link to clipboard

Copied

The script that you wrote and the one that I have in production are pretty similiar and are quite fast, I have been dealing with documents with more that 6000 character styles and 4000 odd paragraph style and the speeds are fine(automated style creation and then users coming in and deleting contents). The slowness that I encountered was when trying to delete unused styles, I was able to get the list of unused styles pretty fast but then deleting make the application to crawl. Now I am curious how the idea from Robert would work, who knows it could be multitudes of times faster than our approach. When I get time I will work on it and share my results.

-Manan

Votes

Translate

Translate

Report

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 ,
Dec 28, 2022 Dec 28, 2022

Copy link to clipboard

Copied

But Robert's idea won't remove the styles... unless you plan to actually use the document-with-duplicated-pages for real. So if the slow part is removing the styles I wonder if it will be much improvement? I will be interested to hear your results. - Mark

 

P.S. Documents with more than 6000 character styles and 4000 paragraph styles... OMG!

Votes

Translate

Translate

Report

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 ,
Dec 29, 2022 Dec 29, 2022

Copy link to clipboard

Copied

Yeah 😄 6000 & 4000 ?!?! Someone lost their plot 😉

 

In JS you have this cool thing - everyItem() - it should be a breeze to compare all the styles between documents?? 

 

Just get the list of names - for each level - sort alphabetically and compare - would be waaaay quicker than my example - requesting reference and checking for error 😉 

 

▒► ID-Tasker / ID-Tasker Server - work smart not hard ◄▒

Votes

Translate

Translate

Report

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 ,
Dec 29, 2022 Dec 29, 2022

Copy link to clipboard

Copied

I don't think there is a way to speed up the process of deleting styles... 

 

But will ask, just in case 😉 have you turned off redraw for script? 

Or turned off UNDO? THIS should speed up things... 

 

Or save document - with a new name would be best - THEN cleanup your document - file will be lighter and fresh and no Undo history so should work much faster...

 

▒► ID-Tasker / ID-Tasker Server - work smart not hard ◄▒

Votes

Translate

Translate

Report

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 ,
Dec 29, 2022 Dec 29, 2022

Copy link to clipboard

Copied

Hi @Robert Tkaczyk and @m1b,

Well yes I tried multiple things when I was trying to delete the styles and nothing came to acceptable limits. Even deletion from the UI panel for this amount of styles does create a noticeable lag so I think we hit the wall there. Since I just wanted to know the names of the styles used, I changed tracks and stopped deletion of the styles altogether.

Well yes the number of styles is insane, it cropped up from a situation where the file creators did not agree to be consistent with using styles. They send out files with overrides then I have a script that converts the overrides to actual styles, then again these files land with the artists who can do all sort of things including deleting content but not deleting the styles and over a period of time with the style creation script running and new overrides being created we end up in this situation. The developers and the file creators seldom agree on a common thing is what has been my expereince so far.

-Manan

Votes

Translate

Translate

Report

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 ,
Dec 29, 2022 Dec 29, 2022

Copy link to clipboard

Copied

I was just thinking 😉 and I'm not sure if getting names of the unused styles is the main / only objective for the OP - he needs the info about (un)used styles to grade the students - but I've just got a brilliant idea / solution for you @Manan Joshi 😄

 

If YOUR objective is to get rid of unused styles / colors / etc. ........ just copy / move pages to a new document 😄

 

In a way it's like IDMLing 😉 gets rid of junk 😉 

 

▒► ID-Tasker / ID-Tasker Server - work smart not hard ◄▒

Votes

Translate

Translate

Report

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 ,
Dec 30, 2022 Dec 30, 2022

Copy link to clipboard

Copied

I'm missing a discussion whether having unused styles should really influence a grade. Sure, they can use the find-unused menu action and eventually delete. But I'd be curious about the assumed scenario where this really matters ...

Then there are so many possible ways where styles are used according to find-unused, but aren't in the actual document. For example you have a paragraph style used as based-on style of other pstyles, and that refers to character styles. From the bullet settings - disabled and thus not directly reachable in UI, but it is still there, and would get picked up by the dependent pstyle with the bullet. Or the other character style referenced by the not-triggered grep style, line style or other run-in style. The dependent styles might override all of these usages - different greps, or apply different cstyle. Would you still consider it used in the basic style? Even if that derived pstyle is only used by a toc style within a document that makes no use of a toc? And so forth.

Same for paragraph styles referenced by object styles, even if the ostyle is applied the pstyle might not end up applied to text because the user applied another one later on. Have you considered cell styles? I'd have to look whether they can reference text styles. Or, think about the paragraph style from the next style setting. Another one is only applied to the page number frame on the unused master page. The dark red cstyle applied only to the one space, or changing an underline color where there are no underlines? Are the students really supposed to track all those locations down? Give them a thought?

The document is either considered final, then cleaning up those styles would be a bad use of working time, or the document is awaiting further revisions where those currently unused styles might come in handy and a consistent set of styles is far more relevant than actual use or space-saving. You may want to import the style set into the next document, why would you want to re-create that paragraph style for list items, just because the earlier document did not use it?

Votes

Translate

Translate

Report

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 ,
Dec 31, 2022 Dec 31, 2022

Copy link to clipboard

Copied

Hi @Dirk Becker, you make some interesting and valid points. For my part in this, you have pointed out some shortcomings in my script that I will be keen to investigate/address when I have the time.

- Mark

Votes

Translate

Translate

Report

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 ,
Jan 03, 2023 Jan 03, 2023

Copy link to clipboard

Copied

Hi @m1b , I have produced a list across the object model where character styles are referenced. Some repetitions across the various text types, but it also covers some seen places. Ignore the methods, e.g. CellStyleGroup.remove() takes a style argument and the argument declaration is just wrong.

On the other hand I just learned there is a MatchCharacterStylePreference used for running header variables ...

Bildschirmfoto 2023-01-03 um 19.14.42.png

 

Votes

Translate

Translate

Report

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 ,
Jan 03, 2023 Jan 03, 2023

Copy link to clipboard

Copied

Thanks Dirk, that'll be a good guide. - Mark

Votes

Translate

Translate

Report

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 ,
Jan 03, 2023 Jan 03, 2023

Copy link to clipboard

Copied

Are we still looking for a way to find unused styles or it's just a list of places where styles are mentioned? 

 

▒► ID-Tasker / ID-Tasker Server - work smart not hard ◄▒

Votes

Translate

Translate

Report

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