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

need help with IndexOf function not working

Explorer ,
May 16, 2025 May 16, 2025
var doc = app.activeDocument;
var counter = 1;

for (var i = 0; i < doc.pages.length; i++) {
    var page = doc.pages[i];

    // Create a text frame on the page
    var tf = page.textFrames.add({
        geometricBounds: [20, 20, 100, 100] // Adjust as needed
    });

    // Find all footnotes on the page by iterating through all stories in the document
    var stories = doc.stories;
    alert("Found " + stories.length + " stories.");
        var s = stories[0];
        // Check if any text frame of this story is on the current page
        var frames = s.textContainers;
        var isOnPage = false;
        for (var t = 0; t < frames.length; t++) {
            if (frames[t].parentPage && frames[t].parentPage == page) {
                isOnPage = true;
                break;
            }
        }
        if (!isOnPage) continue;

        var fns = s.footnotes;
        alert("Found " + fns.length + " footnotes in story " + (s + 1) + ".");
        // Iterate through all footnotes in the story

        for (var f = 0; f < fns.length; f++) {
            // Find paragraphs in footnote that begin with "حاشية"
            var paras = fns[f].paragraphs;
            // alert("Found " + paras.length + " paragraphs in footnote " + (f + 1) + ".");
            for (var p = 0; p < paras.length; p++) {
                // alert(paras[p].contents);
// this line is not working. there are pragraphs that start with prefix text, but the if statement doesn't catch them (need help here)
                 if (paras[p].contents.indexOf(":حاشية") === 0) {
                    // Cut the paragraph text
                    var paraText = paras[p].contents;
                    alert("Found footnote: " + paraText);
                    paras[p].remove();

                    // Replace footnote marker in main text with counter
                    var marker = fns[f].storyOffset;
                    marker.contents = counter.toString() + " ";
                    // delete the footnote marker
                    // works but in next iteration length of fns changes and error occurs
                    // fns[f].remove();

                    // Insert counter and text in created text frame
                    tf.contents += counter + "- " + paraText;

                    counter++;
                }
             }
        }
}
alert("Finished processing footnotes.");

this is what i want to achieve from above code:

1- create a textframe on each page
2- on that page, select all paragraphs in footnote that begin with ":حاشية"
3- cut that text to clipboard
4- maintain a counter and increment it on each find
5- insert counter number in place of footnote marker in main text and remove footnote marker
6- insert the counter number in text frame created earlier, paste the text from clipboard after the number
 
step 2 is not working with indexOf.
step 5 deletes footnote marker but causes error.
need help to resolve this.
thanks.
TOPICS
Scripting
1.5K
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 , May 17, 2025 May 17, 2025

Hi @Moiz5FB2 I had a look at your script so far and I have re-written it the way I would like it. This can be just for your learning, it doesn't mean you must do it this way—there are many correct ways—but just that I prefer this approach.

 

Here are some notes to help:

 

1. The script starts by collecting all the footnotes matching the target text at the start using findGrep and stores the contents and a reference to the footnote marker in the main story.

 

It stores a {contents: 'my footnote s

...
Translate
LEGEND ,
May 16, 2025 May 16, 2025

Try using Find&Change to find your text - then process the results - it will save you time of checking every Story and every Paragraph.

 

Maybe the search phrase you've entered - is "beyond" JS Unicode capabilities? 

 

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
Explorer ,
May 16, 2025 May 16, 2025

i guessed that too and tried with english footnote text and it did not 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
LEGEND ,
May 16, 2025 May 16, 2025
quote

i guessed that too and tried with english footnote text and it did not work.


By @Moiz5FB2

 

What exactly have you tried? 

 

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
LEGEND ,
May 16, 2025 May 16, 2025

@Moiz5FB2 

 

My idea is to use InDesign's F&C - and either type text in the "Find What:" field and then run script (*) that will work with findText() or findGREP() - or save the Query:

RobertatIDTasker_0-1747403382900.png

and then load it in the script - at the beginning.

 

 

(*) could work like this: 

 

RobertatIDTasker_1-1747403688620.png

 

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 ,
May 16, 2025 May 16, 2025

Try replace this

if (paras[p].contents.indexOf(":حاشية") === 0) {

With:

var content = paras[p].contents.replace(/[\u200E\u200F\u202A-\u202E\uFEFF]/g, "").trim(); // Remove hidden LTR/RTL markers
if (content.indexOf(":حاشية") === 0) {

 Should remove invisible characters (Unicode directionality marks), and trims whitespace that could break your match.

 

Try to iterate backwards

replace

for (var f = 0; f < fns.length; f++) {

with

for (var f = fns.length - 1; f >= 0; f--) {

 

 

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
Explorer ,
May 16, 2025 May 16, 2025

thanks for prompt reply.

tried the changes and got this error:

 

JavaScript Error!

Error Number: 24
Error String: paras[p].contents.replace().trim is not a function

Source: var content = paras[p].contents.replace(/[\u200E\u200F\u202A-\u202E\uFEFF]/g, "").trim();

 

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 ,
May 16, 2025 May 16, 2025

Ah right sorry about that 

 

var content = String(paras[p].contents).replace(/[\u200E\u200F\u202A-\u202E\uFEFF]/g, "").trim();

 If you have a sample file I can troubleshoot the script to see if I can get it working for you

 

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
Explorer ,
May 16, 2025 May 16, 2025

sample file provided.

script is the same as initially posted.

 

thanks for your time and kind help.

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 ,
May 16, 2025 May 16, 2025

@Moiz5FB2 - I haven't tested the attached file yet, but for the trim functionality to work within the script, you'll need to include its prototype definition:

if (!String.prototype.trim) {
    (function () {
        // Ensures trimming of BOM and non-breaking spaces (NBSP)
        var rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;
        String.prototype.trim = function () {
            return this.replace(rtrim, '');
        };
    })();
}

 

Best regards
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
Explorer ,
May 16, 2025 May 16, 2025

thanks for the suggested code for trim, now no more errors with trim.

but the below code still does not work:

for (var f = fns.length - 1; f >= 0; f--) {
            // Find paragraphs in footnote that begin with "حاشية"
            var paras = fns[f].paragraphs;
            // alert("Found " + paras.length + " paragraphs in footnote " + (f + 1) + ".");
            for (var p = 0; p < paras.length; p++) {
                // Remove hidden LTR/RTL markers
                var content = String(paras[p].contents).replace(/[\u200E\u200F\u202A-\u202E\uFEFF]/g, "").trim();
                alert(content);
                if (content.indexOf("a") === 0) {
                    // Cut the paragraph text
                    var paraText = paras[p].contents;
                    alert("Found footnote: " + paraText);
                    paras[p].remove();

                    // Replace footnote marker in main text with counter
                    var marker = fns[f].storyOffset;
                    marker.contents = counter.toString() + " ";
                    // delete the footnote marker
                    // works but in next iteration length of fns will change and error will occur
                    // fns[f].remove();

                    // Insert counter and text in created text frame
                    tf.contents += counter + "- " + paraText;

                    counter++;
                }
            }
        }

the "alert(content);" shows all footnote contents correctly, but in next line indexOf fails to detect anything. 

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 ,
May 16, 2025 May 16, 2025

I'm not having much luck either 

 

On the surface it should be working but I'm missing something - I build in a few checks to see what's going on, and can get a sample return, but I am lost 

@m1b @Charu Rajput any ideas what's going wrong? 

Fairly new to scripting - hope it's something simple. 

if (!String.prototype.trim) {
    String.prototype.trim = function () {
        return this.replace(/^\s+|\s+$/g, '');
    };
}

var doc = app.activeDocument;
var counter = 1;

for (var i = 0; i < doc.pages.length; i++) {
    var page = doc.pages[i];

    var tf = page.textFrames.add({
        geometricBounds: [20, 20, 100, 100]
    });

    var stories = doc.stories;

    for (var s = 0; s < stories.length; s++) {
        var story = stories[s];
        var frames = story.textContainers;
        var isOnPage = false;

        for (var t = 0; t < frames.length; t++) {
            if (frames[t].parentPage && frames[t].parentPage === page) {
                isOnPage = true;
                break;
            }
        }
        if (!isOnPage) continue;

        var fns = story.footnotes;

        for (var f = fns.length - 1; f >= 0; f--) {
            var paras = fns[f].paragraphs;

            for (var p = 0; p < paras.length; p++) {
                var content = String(paras[p].contents)
                    .replace(/[\u200E\u200F\u202A-\u202E\uFEFF]/g, "")
                    .trim();

                alert("Checking paragraph: " + content);

                var pattern = /^[:\u0600-\u06FF]/;

                if (pattern.test(content)) {
                    alert("Matched paragraph: " + content);

                    var paraText = paras[p].contents;
                    paras[p].remove();

                    var marker = fns[f].storyOffset;
                    marker.contents = counter.toString() + " ";

                    tf.contents += counter + "- " + paraText + "\r";

                    counter++;

                    fns[f].remove();

                    break;
                }
            }
        }
    }
}

alert("Finished processing footnotes.");



 

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
Explorer ,
May 16, 2025 May 16, 2025

I asked ChatGPT about this and it suggested this:

alert(content.charCodeAt(0));
which shows 4 for all footnotes.
 
Hope that might help in troubleshooting .
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
Explorer ,
May 16, 2025 May 16, 2025
var doc = app.activeDocument;
var counter = 1;

if (!String.prototype.trim) {
    (function () {
        // Ensures trimming of BOM and non-breaking spaces (NBSP)
        var rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;
        String.prototype.trim = function () {
            return this.replace(rtrim, '');
        };
    })();
}

for (var i = 0; i < doc.pages.length; i++) {
    var page = doc.pages[i];

    // Create a text frame on the page
    var tf = page.textFrames.add({
        geometricBounds: [20, 20, 100, 100] // Adjust as needed
    });

    // Find all footnotes on the page by iterating through all stories in the document
    var stories = doc.stories;
    // alert("Found " + stories.length + " stories.");
        var s = stories[0];
        // Check if any text frame of this story is on the current page
        var frames = s.textContainers;
        var isOnPage = false;
        for (var t = 0; t < frames.length; t++) {
            if (frames[t].parentPage && frames[t].parentPage == page) {
                isOnPage = true;
                break;
            }
        }
        if (!isOnPage) continue;

        var fns = s.footnotes;

        // Iterate through all footnotes in the story
        for (var f = fns.length - 1; f >= 0; f--) {
            var paras = fns[f].paragraphs;
            // for (var p = 0; p < paras.length; p++) {
            for (var p = paras.length-1; p >=0; p--) {
                var content = paras[p].contents;
                alert(content);
                if (endsWithArabicWord(content, "(حاشية)")) {
                    // Cut the paragraph text
                    var paraText = paras[p].contents;
                    // alert("Found footnote: " + paraText);
                    paras[p].remove();

                    // Replace footnote marker in main text with counter
                    var marker = fns[f].storyOffset;
                    marker.contents = counter.toString() + " ";
                    // delete the footnote marker
                    fns[f].remove();

                    // Insert counter and text in created text frame
                    tf.contents += counter + "- " + paraText;

                    counter++;
                }
            }
        }
}
alert("Finished processing footnotes.");

function endsWithArabicWord(text, word) {
  if (text == null || word == null) return false;

  // Fallback trim (remove leading/trailing spaces)
  text = text.replace(/^\s+|\s+$/g, '');

  // Escape special regex characters in the word
  var safeWord = word.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');

  // Check for optional space or punctuation before the word
  var pattern = new RegExp("[\\s\\u060C\\u061B\\u061F\\u0640\\u200C\\u200F\\u202B\\u200E\\u202C\\u202D\\u202E]*" + safeWord + "$");

  return pattern.test(text);
}

I changed the strategy, now i process all paragraphs that end with particular word.

the above code works as expected.

now the issue is that the loops run backwards to avoid length errors.
because of that the marker numbers in body text are inserted in reverse order.

please provide your expert help and suggestions on this.

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 ,
May 17, 2025 May 17, 2025

Hi @Moiz5FB2 I had a look at your script so far and I have re-written it the way I would like it. This can be just for your learning, it doesn't mean you must do it this way—there are many correct ways—but just that I prefer this approach.

 

Here are some notes to help:

 

1. The script starts by collecting all the footnotes matching the target text at the start using findGrep and stores the contents and a reference to the footnote marker in the main story.

 

It stores a {contents: 'my footnote string here', marker: FOOTNOTE_SYMBOL} object in an array, organised by in the footnoteDetailsByPage object accessed by the page's document offset. This is the most complex part I think if you haven't stored properties in plain Objects before. For example we can access it like this:

var secondFootnoteMarkerOnPageOne = footnoteDetailsByPage[0][1].marker;
var sixthFootnoteContentsOnPageThree = footnoteDetailsByPage[2][5].contents;
var countOfFootnotesProcessedOnPageFive = footnoteDetailsByPage[4].length;

This is what it looks like in the debugger, after running your sample document with my boxes added:

Screenshot 2025-05-17 at 20.33.56.png

2. After collecting the info in footnoteDetailsByPage, we start a new loop, going over every page stored in footnoteDetailsByPage and then looping over every element of the array stored there. We go forwards so the indexing will be easier.

 

3. I've wrapped whole script in the app.doScript call.

app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, 'Process Footnotes');

This is very important for a script like this, because it means that you can undo the whole script's work in one go.

 

4. To see more of what is happening, I collect "results" and show them at the end.

 

I hope that can be useful to you.

- Mark

 

function main() {

    var doc = app.activeDocument;

    // set up the find grep
    app.findGrepPreferences = NothingEnum.NOTHING;
    app.findChangeGrepOptions.includeFootnotes = true;
    app.findChangeGrepOptions.includeHiddenLayers = false;
    app.findChangeGrepOptions.includeLockedLayersForFind = false;

    // find footnote texts starting with "footnote:"
    app.findGrepPreferences.findWhat = '^~F\\s*حاشية:';

    var footnoteTexts = doc.findGrep();

    if (!footnoteTexts)
        return alert('Could not find any footnotes.');

    // we will store all the contents here, organised by page index
    var footnoteDetailsByPage = {};

    // collect details for each matched footnote, then remove it
    for (var i = footnoteTexts.length - 1; i >= 0; i--) {

        var footnote = footnoteTexts[i].parent,
            page = footnote.characters[0].parentTextFrames[0].parentPage;

        if (!footnoteDetailsByPage[page.documentOffset])
            // initialize with a new array
            footnoteDetailsByPage[page.documentOffset] = [];

        // add details about this footnote
        footnoteDetailsByPage[page.documentOffset].unshift({
            // remove hidden LTR/RTL markers and trim whitespace
            contents: footnote.contents.replace(/^\s+|\s+$|[\u200E\u200F\u202A-\u202E\uFEFF]/g, ""),
            // we need this for later
            marker: footnote.storyOffset.parentStory.characters[footnote.storyOffset.index],
        });

        // remove the footnote
        footnoteTexts[i].remove();

    }

    var results = [];

    // process each page
    for (var pageOffset in footnoteDetailsByPage) {

        if (!footnoteDetailsByPage.hasOwnProperty(pageOffset))
            continue;

        var page = doc.pages[pageOffset];
        var footnoteDetailsForThisPage = footnoteDetailsByPage[pageOffset];
        var contents = [];

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

            var footnoteDetail = footnoteDetailsForThisPage[i];

            // replace the footnote marker with the current index
            footnoteDetail.marker.contents = String(i + 1);

            // add the contents to this page's contents list
            contents.push((i + 1) + '- ' + footnoteDetail.contents);

        }

        // create a text frame on the page, with contents from each processed footnote
        var tf = page.textFrames.add({
            geometricBounds: [20, 20, 100, 100], // Adjust as needed
            contents: contents.join('\r'),
        });

        results.push('Page ' + page.name + ': matched ' + contents.length + ' footnotes.')

    }

    alert("Finished processing footnotes.\n" + results.join('\n'));

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

Edit: added image for clarity.

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
Explorer ,
May 18, 2025 May 18, 2025

 

Thank you very much for the perfectly functioning code and the clear, detailed explanation of your approach and the steps you followed to achieve the desired outcome.
I truly appreciate the time and effort you saved me.
Thanks again, with best regards.

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 ,
May 18, 2025 May 18, 2025
LATEST

I'm glad to hear it was helpful. All the best with your 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
LEGEND ,
May 17, 2025 May 17, 2025

@Moiz5FB2

 

You're working with contents of the found results - instead of the Text object.

 

If you use InDesign's functionality to search for text - text or GREP - you'll avoid all your problems. 

 

You'll also preserve formatting. 

 

Looks like Mark already addressed most of it.

 

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