Skip to main content
SuzzyFlamingo
Inspiring
September 1, 2025
Answered

Script to collect styled footnote text into a single frame

  • September 1, 2025
  • 1 reply
  • 683 views

I couldn't write a JavaScript if my life depended on it, so I am forced to bother you all friends if someone can assist me with this:

I need to scan the current doc and pick up every text string with the par style "sty1" then dump all those instances into a new text frame at the end of the doc with a acsemi colon between them. But there is a little tricky issue here: these strings will always be in the footnote area. Now on many pages there are two text frames, on the top A and on the bottom B. Each one could have FN with that par style. But it is crucial *that the order be by entire page*, so it should scan the FN of text frame A on page 1 and then text of the FN on frame B on page 1 and then proceed to page 2 and repeat again etc.

 

So if on page 1 in text frame A, we have a footnote (again in frame A) with the formatted text "I love cheesecake" and another formatted FN "I love soda" and then in frame B (on page 1) we have in the FN the formatted text "I love walnuts " and then on *page 2* in frame A we have the FN with formatted text  the formatted text FN "Go on a diet" and then in frame B (on page 2) in the FN we have the formatted text "you are getting fat" it should create, at the end of the doc a new text frame with the text:

"I love cheesecake cake; I love soda; I love walnuts; go on a diet; you are getting fat"

 

Can this be done?

 

Thank you very much

SF

 

 

<Title renamed by MOD>

Correct answer m1b

Hi @SuzzyFlamingo if I understand you right, this script should do it.

- Mark

 

/**
 * @file Collect Styled Footnotes On Last Page.js
 *
 * Note: sorts footnotes by page index and baseline position.
 *
 * @author m1b
 * @version 2025-09-04
 * @discussion https://community.adobe.com/t5/indesign-discussions/looking-for-script/m-p/15485013
 */
function main() {

    var settings = {
        delimiter: '; ',
        findStyleName: 'sty1',
        addNewPage: true,
    };

    var doc = app.activeDocument;
    var findStyle = getThing(doc.allParagraphStyles, 'name', settings.findStyleName);

    if (!findStyle)
        return alert('No style "' + settings.findStyleName + '" found.');

    var found = findText(doc, { appliedParagraphStyle: settings.findStyleName });

    var cleanUpContents = /^\u0004?\s|\s*$/g;
    var found2 = [];

    // collect the footnotes contents and positions
    for (var i = 0; i < found.length; i++) {

        if (
            !found[i].parentTextFrames[0].parentPage.isValid
            || 'Footnote' !== found[i].parent.constructor.name
        )
            // ignore text on the pasteboard or non-footnote text
            continue;

        found2.push({
            position: found[i].parentTextFrames[0].parentPage.documentOffset * 10000 + found[i].baseline,
            contents: found[i].contents.replace(cleanUpContents, '')
        });

    }

    if (0 === found2.length)
        return alert('No footnotes texts found.');

    // sort by position ascending
    found2.sort(function (a, b) { return a.position - b.position });

    // join contents
    var allContents = [];
    for (var i = 0; i < found2.length; i++)
        allContents.push(found2[i].contents);

    if (settings.addNewPage)
        doc.pages.add(LocationOptions.AT_END, doc);

    var lastPage = doc.pages.lastItem();

    var newFrame = lastPage.textFrames.add(
        {
            geometricBounds: [lastPage.bounds[0], lastPage.bounds[1], 50, lastPage.bounds[3]],
            strokeWidth: 0,
            fillColor: "None",
            contents: allContents.join(settings.delimiter),
        }
    );

};
app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, 'Collect Styled Footnotes');

/**
 * Returns result of search in the supplied `findIn` object
 * using its findText method.
 *
 * Example:
 *    var headingParas = findText(doc, { appliedParagraphStyle: headingStyle });
 *
 * @author m1b
 * @version 2025-04-18
 * @param {Document|Text} findIn - any object with a valid `findText` method.
 * @param {Object} findWhat - an object containing findChangeTextOptions properties.
 * @returns {Array<Text>}
 */
function findText(findIn, findWhat) {

    if ('function' !== typeof findIn.findText)
        throw new Error('findText: bad `where` supplied.');

    // configure the find
    app.findChangeTextOptions.properties = {
        caseSensitive: false,
        includeFootnotes: true,
        includeHiddenLayers: false,
        includeLockedLayersForFind: false,
        includeLockedStoriesForFind: false,
        includeMasterPages: false,
        wholeWord: false,
    };

    // reset
    app.findTextPreferences = NothingEnum.NOTHING;

    // configure the find with settings
    for (var key in findWhat) {

        if (
            findWhat.hasOwnProperty(key)
            && app.findTextPreferences.hasOwnProperty(key)
        )
            app.findTextPreferences[key] = findWhat[key];

    }

    // perform the find
    return findIn.findText();

};

/**
 * Returns a thing with matching property.
 * If `key` is undefined, evaluate the object itself.
 * @author m1b
 * @version 2024-04-21
 * @param {Array|Collection} things - the things to look through.
 * @param {String} [key] - the property name (default: undefined).
 * @param {*} value - the value to match.
 * @returns {*?} - the thing, if found.
 */
function getThing(things, key, value) {

    for (var i = 0; i < things.length; i++)
        if ((undefined == key ? things[i] : things[i][key]) == value)
            return things[i];

};

Edit 2025-09-04: added sorting of found footnotes, based on page index and baseline position.

Edit 2025-09-04: added option to create a new page for the results.

Edit 2025-09-04: removed requirement to only collect Footnotes.

Edit 2025-09-04: added Footnote requirement back in 🙂

1 reply

m1b
Community Expert
m1bCommunity ExpertCorrect answer
Community Expert
September 1, 2025

Hi @SuzzyFlamingo if I understand you right, this script should do it.

- Mark

 

/**
 * @file Collect Styled Footnotes On Last Page.js
 *
 * Note: sorts footnotes by page index and baseline position.
 *
 * @author m1b
 * @version 2025-09-04
 * @discussion https://community.adobe.com/t5/indesign-discussions/looking-for-script/m-p/15485013
 */
function main() {

    var settings = {
        delimiter: '; ',
        findStyleName: 'sty1',
        addNewPage: true,
    };

    var doc = app.activeDocument;
    var findStyle = getThing(doc.allParagraphStyles, 'name', settings.findStyleName);

    if (!findStyle)
        return alert('No style "' + settings.findStyleName + '" found.');

    var found = findText(doc, { appliedParagraphStyle: settings.findStyleName });

    var cleanUpContents = /^\u0004?\s|\s*$/g;
    var found2 = [];

    // collect the footnotes contents and positions
    for (var i = 0; i < found.length; i++) {

        if (
            !found[i].parentTextFrames[0].parentPage.isValid
            || 'Footnote' !== found[i].parent.constructor.name
        )
            // ignore text on the pasteboard or non-footnote text
            continue;

        found2.push({
            position: found[i].parentTextFrames[0].parentPage.documentOffset * 10000 + found[i].baseline,
            contents: found[i].contents.replace(cleanUpContents, '')
        });

    }

    if (0 === found2.length)
        return alert('No footnotes texts found.');

    // sort by position ascending
    found2.sort(function (a, b) { return a.position - b.position });

    // join contents
    var allContents = [];
    for (var i = 0; i < found2.length; i++)
        allContents.push(found2[i].contents);

    if (settings.addNewPage)
        doc.pages.add(LocationOptions.AT_END, doc);

    var lastPage = doc.pages.lastItem();

    var newFrame = lastPage.textFrames.add(
        {
            geometricBounds: [lastPage.bounds[0], lastPage.bounds[1], 50, lastPage.bounds[3]],
            strokeWidth: 0,
            fillColor: "None",
            contents: allContents.join(settings.delimiter),
        }
    );

};
app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, 'Collect Styled Footnotes');

/**
 * Returns result of search in the supplied `findIn` object
 * using its findText method.
 *
 * Example:
 *    var headingParas = findText(doc, { appliedParagraphStyle: headingStyle });
 *
 * @author m1b
 * @version 2025-04-18
 * @param {Document|Text} findIn - any object with a valid `findText` method.
 * @param {Object} findWhat - an object containing findChangeTextOptions properties.
 * @returns {Array<Text>}
 */
function findText(findIn, findWhat) {

    if ('function' !== typeof findIn.findText)
        throw new Error('findText: bad `where` supplied.');

    // configure the find
    app.findChangeTextOptions.properties = {
        caseSensitive: false,
        includeFootnotes: true,
        includeHiddenLayers: false,
        includeLockedLayersForFind: false,
        includeLockedStoriesForFind: false,
        includeMasterPages: false,
        wholeWord: false,
    };

    // reset
    app.findTextPreferences = NothingEnum.NOTHING;

    // configure the find with settings
    for (var key in findWhat) {

        if (
            findWhat.hasOwnProperty(key)
            && app.findTextPreferences.hasOwnProperty(key)
        )
            app.findTextPreferences[key] = findWhat[key];

    }

    // perform the find
    return findIn.findText();

};

/**
 * Returns a thing with matching property.
 * If `key` is undefined, evaluate the object itself.
 * @author m1b
 * @version 2024-04-21
 * @param {Array|Collection} things - the things to look through.
 * @param {String} [key] - the property name (default: undefined).
 * @param {*} value - the value to match.
 * @returns {*?} - the thing, if found.
 */
function getThing(things, key, value) {

    for (var i = 0; i < things.length; i++)
        if ((undefined == key ? things[i] : things[i][key]) == value)
            return things[i];

};

Edit 2025-09-04: added sorting of found footnotes, based on page index and baseline position.

Edit 2025-09-04: added option to create a new page for the results.

Edit 2025-09-04: removed requirement to only collect Footnotes.

Edit 2025-09-04: added Footnote requirement back in 🙂

SuzzyFlamingo
Inspiring
September 1, 2025

First of all thank you very much.

I ran it on a demo doc and it got the order right on page 2 (first frame  A (at the top of the page) and then frame B (at the bottom, BUT on page 1 it put the FN of frame b (at the bottom) before the FN of frame A (which is at the top) any idea what happened?

 

m1b
Community Expert
Community Expert
September 1, 2025

Not yet. I can't reproduce it here. Even if I put the text frames on different layers it comes out in the right order in my test document. Can you share a minimal document (change text to lorem upsum if you like) that fails?