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

Trying to make a hyperlinking script

New Here ,
Apr 25, 2025 Apr 25, 2025

Hi,

 

I'm trying to make a script where it will take highlighted text, make it into a hyperlink, format it with a character style and make the destination a page within the document, specifically the number that is the highlighted text. The usecase is an index - so I highlight 151, for example, and the script applies the character style "Hyperlink" and makes the text a hyperlink to page 151. Below is what I have so far but I'm tweaking a script I found elsewhere (source below) and I'm really struggling. I'm afraid this is not a particular strength of mine.

 

If anyone fancies digging into it and seeing if they can make it work, I'd be very grateful! 

Thanks, Eubhal

 

Script:

 

Main();
// If you want the script to be un-doable, comment out the line above, and remove the comment from the line below
// app.doScript(Main, undefined, undefined, UndoModes.ENTIRE_SCRIPT,”Run Script”);

function Main() {
//This takes the text that you have highlighted on the page
var myHighlightedText = app.selection[0].contents;

//this checks that you have selected some text (with a length greater than 1). If not it will tell you to select some text.
if(myHighlightedText.length < 1){
alert("No text has been selected");
}

//This targets the text frame which the highlighted text is within
var myTextFrame = app.selection[0].parentTextFrames[0];

//The highlighted text in Indesign is just a plain string – which is not an object in InDesign and therefore cannot be formatted via InDesign styles.
//This gets the index number from the start of the selected text
var styleStartIndex = app.selection[0].index;
//This gets the index number from the end of the highlighted text
var styleEndIndex = styleStartIndex + myHighlightedText.length-1;

//select the text by their index numbers previously defined.
var mySelection = myTextFrame.characters.itemByRange(styleStartIndex, styleEndIndex);
//apply the character style to it.
mySelection.appliedCharacterStyle="Hyperlink";

// To take the selected text and add a hyperlink to it, first define both the destination and the source.

//The below defines the source of the hyperlink to be the highlighted text “mySelection”
var source = app.documents[0].hyperlinkTextSources.add(mySelection);
//Destination”s” plural is used because we are selecting (via its name) a single hyperlink destination from the ARRAY of possible destinations.
var dest = app.documents[0].hyperlinkTextDestinations.itemByName("Destination 3");

//this applies the hyperlink referencing the source and the destination
app.documents[0].hyperlinks.add(source,dest, {name:myHighlightedText});

//the {name:myHighlightedText} section is naming the new hyperlink with the text that has been selected.

}

Original source: https://creativepro.com/topic/indesign-scripting-hyperlinks/

TOPICS
Scripting
2.4K
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 , Apr 25, 2025 Apr 25, 2025

Hi @Eubhal okay I see, well I'll just remove the part that tries to re-used an existing page destination and it will create a new one each time (same as your manual way). I'll leave the other script up though, because it is a better approach. So using your workflow, just select text containing one or more numbers and it will create hyperlinks for them. So you could select just the "1" or Apple 1,3,5 or the whole line to create 3 hyperlinks at once.

- Mark

/**
 * @file Add Hyperlinks For Page Num
...
Translate
Community Expert ,
Apr 25, 2025 Apr 25, 2025

Hi @Eubhal this looks like it might be a better use for Cross References. They have the advantage that, even if the pages change, the links will still follow them. In any case, could you create a small sample .indd document and post here for us to look at—maybe one before and one after the script is run. That is a good way to make your expectations clear.

- Mark

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
New Here ,
Apr 25, 2025 Apr 25, 2025

Thanks m1B! I'm afraid the script is not currently running without errors so no after file is possible yet. I can make up something to show what I'm working on though. Cross-references looks a lot more complex than what I'm needing for this - the references won't change later, the main issue is that there are a lot of entries so I'm trying to automate as much as I can per entry - preferably just highlight, run script, done. It occurs to me that it's essentially the same as the Convert URLs to hyperlinks feature but that the destination needs to be page rather than url and that that feature only works on text it has found but fundamentally the same idea. I'll make up an example file and comment again with it. Thanks again for your time!

Eubhal

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 ,
Apr 25, 2025 Apr 25, 2025

@Eubhal just to clarify—yes it does sound like you could use some automation here. The only question is the best way to go about it. Cross References actually have hyperlinks as part of them (when you make them programatically you need to create a hyperlink). When I asked for a sample document, I don't mean *after* your script is run, I mean a page (or two if necessary) of manually created hyperlinks to show what you expect a hypothetical script to produce. Mainly it needs to show what the source text looks like. It sounds like you are saying the source text is just a number. Are they set in a character style or anything, or do you just need to find them by hand?

- Mark

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
New Here ,
Apr 25, 2025 Apr 25, 2025

I would just be finding them by hand and highlighting them

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
New Here ,
Apr 25, 2025 Apr 25, 2025

I just threw these together and did the first link on the index so you can see what I'm looking for. Any thoughts or solutions would be appreciated. Thanks so much for stopping to help!

Eubhal

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 ,
Apr 25, 2025 Apr 25, 2025

@Eubhal 

 

OK, took a look at your INDD file...

 

So you just want an Index??

 

Why not doing it the "right" way - index all words and let InDesign do the "dirty work" 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
LEGEND ,
Apr 25, 2025 Apr 25, 2025

@Eubhal

 

Some scripts from @Peter Kahrel:

 

https://creativepro.com/files/kahrel/indesign/lists_indexes.html 

 

There is a script to index all words / phrases from a list. 

 

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 ,
Apr 25, 2025 Apr 25, 2025

As Robert said, it does seem like you are creating a standard index. Can you elaborate on why an ordinary index isn't the right way to go in your case?

 

Edit: oh wait! Do you mean the "index"—dumb, with no cross references—is already existing and you just need to link to the pages specified there?

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
New Here ,
Apr 25, 2025 Apr 25, 2025

Yes, exactly that! 🙂 It's not my file, I just have the burdensome task of linking the numbers already present to their pages. That's all they want done.

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 ,
Apr 25, 2025 Apr 25, 2025
quote

Yes, exactly that! 🙂 It's not my file, I just have the burdensome task of linking the numbers already present to their pages. That's all they want done.


By @Eubhal

 

Then the easiest way would be to find all numbers in this Story - using GREP - then use the returned collection to create Hyperlinks / Cross-References. 

 

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 ,
Apr 25, 2025 Apr 25, 2025

Okay got it, @Eubhal. Here's a script that might do what you want. Select the "index" text and run it.

- Mark

demo.gif

/**
 * @file Add Hyperlinks For Page Numbers.js
 * 
 * Usage:
 *   1. Select the existing "index" text
 *      - can be a text frame or some selected
 *        text or a whole story
 * 
 *   2. Run script
 *
 * @author m1b
 * @version 2025-04-25
 * @discussion https://community.adobe.com/t5/indesign-discussions/trying-to-make-a-hyperlinking-script/m-p/15288981
 */
function main() {

    var settings = {
        hyperlinkCharacterStyleName: 'Hyperlink',
    }

    var doc = app.activeDocument,
        target = doc.selection[0];

    if (
        undefined == target
        || 'function' !== typeof target.findGrep
    )
        return alert('Please select the index text and try again.');

    var characterStyle = getThing(doc.allCharacterStyles, 'name', settings.hyperlinkCharacterStyleName);

    if (!characterStyle)
        return alert('Could not find "' + settings.hyperlinkCharacterStyleName + '" character style.');

    // clear the find/change grep preferences
    app.findGrepPreferences = NothingEnum.nothing;
    // set the find options
    app.findChangeGrepOptions.includeFootnotes = false;
    app.findChangeGrepOptions.includeHiddenLayers = false;
    app.findChangeGrepOptions.includeLockedLayersForFind = false;
    app.findChangeGrepOptions.includeLockedStoriesForFind = false;
    app.findChangeGrepOptions.includeMasterPages = false;
    // set the grep to search for page numbers
    app.findGrepPreferences.findWhat = '\\d+';
    // perform the find
    var found = target.findGrep();

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

        var text = found[i],
            page = getThing(doc.pages, 'name', text.contents);

        if (!page)
            continue;

        // remove existing hyperlink
        var existing = text.findHyperlinks();
        for (var j = existing.length - 1; j >= 0; j--)
            existing[j].remove();

        var source = doc.hyperlinkTextSources.add(text);

        var destination = (
            getThing(doc.hyperlinkPageDestinations, 'destinationPage', page)
            || doc.hyperlinkPageDestinations.add(page, { hidden: false })
        );

        // give the hyperlink a useful name
        var name = text.paragraphs[0].words[0].contents,
            n = 0;

        // a name that won't conflict
        while (doc.hyperlinks.itemByName(name + ' ' + (++n)).isValid);

        // create the hyperlink and name it
        doc.hyperlinks.add(source, destination).name = name + ' ' + n;

        // apply the character style
        text.applyCharacterStyle(characterStyle, true);

    }

};
app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, 'Add Index Hyperinks');

/**
 * 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, obj; i < things.length; i++)
        if ((undefined == key ? things[i] : things[i][key]) == value)
            return things[i];

};

 

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 ,
Apr 25, 2025 Apr 25, 2025

You should rather build GREP search phrase that will work from the end of the line - or skip the beginning - to avoid numbers in the indexed phrases - like "Saturn 5" or "25th Avenue"?

 

And I don't think there is a need for all those "falses" for find options?

 

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
New Here ,
Apr 25, 2025 Apr 25, 2025

Thanks Mark! This looks great but currently I'm getting this error message with it: 

Eubhal_0-1745587293783.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
LEGEND ,
Apr 25, 2025 Apr 25, 2025
quote

Thanks Mark! This looks great but currently I'm getting this error message with it: 

Eubhal_0-1745587293783.png

 


By @Eubhal

 

Do you have hidden spreads in your document? 

 

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 ,
Apr 25, 2025 Apr 25, 2025

@Eubhal that error means that you already have one or more "hidden" hyperlinkPageDestinations in the document. That is bad because you can't share them, for example when "Apple" and "Banana" appear on the same page.

 

Is it possible for you to delete them? Or are they important parts of the document? Go to hyperlink panel menu "Delete unused destinations" or choose "Hyperlink Destination Options" and delete them one by one.

 

I can put a try/catch in the script, but it will mean that some of the index hyperlinks won't work. Better for you to remove hidden destinations.

- Mark

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
New Here ,
Apr 25, 2025 Apr 25, 2025

Thanks Mark. That's a shame but I'm afraid I don't know which ones they are and as I didn't originate the file, I'm not comfortable deleting them/unused destinations. I truly don't need it to be done in one fell swoop - I have to go check each link anyway so I'm fine highlighting a number and just having a script copy the text and stick it in to the hyperlink destination as a page ref and just running that for each number. Right now, I've literally got a programmable keypad set up doing the following:

button 1: copy

button2: create new hyperlink

button 3: paste

button 4: enter

 

Which is grand but pressing one button that does all that per entry would be great, if that's possible. If the hidden destinations would still get in the way of that or if you've just had enough, that's totally fine. Thank you so much for your time and help either way.

 

Eubhal

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
New Here ,
Apr 25, 2025 Apr 25, 2025

Sorry, to be clear, I'd link a button to the script, I'm not asking you to find a button that does that!

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 ,
Apr 25, 2025 Apr 25, 2025

@Eubhal

 

I can't check your file right now - but if you work on Windows - you could use free version of my ID-Tasker tool and load ALL info about ALL interactive Elements - Hyperlinks, Bookmarks, Cross-References, Buttons, etc. 

 

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 ,
Apr 25, 2025 Apr 25, 2025

Hi @Eubhal okay I see, well I'll just remove the part that tries to re-used an existing page destination and it will create a new one each time (same as your manual way). I'll leave the other script up though, because it is a better approach. So using your workflow, just select text containing one or more numbers and it will create hyperlinks for them. So you could select just the "1" or Apple 1,3,5 or the whole line to create 3 hyperlinks at once.

- Mark

/**
 * @file Add Hyperlinks For Page Numbers 4.js
 *
 * Usage:
 *   1. Select the existing "index" text
 *      - can be a text frame or some selected
 *        text or a whole story
 *
 *   2. Run script
 *
 * @author m1b
 * @version 2025-05-09
 * @discussion https://community.adobe.com/t5/indesign-discussions/trying-to-make-a-hyperlinking-script/m-p/15288981
 */
function main() {

    var settings = {
        hyperlinkCharacterStyleName: 'Hyperlink',
    }

    var doc = app.activeDocument,
        target = doc.selection[0];

    if (
        undefined == target
        || 'function' !== typeof target.findGrep
    )
        return alert('Please select the index text and try again.');

    var characterStyle = getThing(doc.allCharacterStyles, 'name', settings.hyperlinkCharacterStyleName);

    if (!characterStyle)
        return alert('Could not find "' + settings.hyperlinkCharacterStyleName + '" character style.');

    // clear the find/change grep preferences
    app.findGrepPreferences = NothingEnum.nothing;
    // set the find options
    app.findChangeGrepOptions.includeFootnotes = false;
    app.findChangeGrepOptions.includeHiddenLayers = false;
    app.findChangeGrepOptions.includeLockedLayersForFind = false;
    app.findChangeGrepOptions.includeLockedStoriesForFind = false;
    app.findChangeGrepOptions.includeMasterPages = false;

    // set the grep to search for page numbers or ranges (~= is endash)
    app.findGrepPreferences.findWhat = '\\d+([~=-]\\d+)?';

    // perform the find
    var found = target.findGrep();

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

        var text = found[i],
            parts = text.contents.split(/[\u2013-]/g),
            entries = [];

        // add the first page number
        entries[0] = {
            text: text.characters.itemByRange(0, parts[0].length - 1),
            pageName: parts[0],
        };

        if (
            2 === parts.length
            && Number(parts[1]) < Number(parts[0])
        ) {

            var secondPageName = parts[0].slice(0, parts[0].length - parts[1].length) + parts[1];

            // expand the second page number, if present
            entries[1] = {
                text: text.characters.itemByRange(text.contents.length - secondPageName.length + 1, secondPageName.length + 1),
                pageName: secondPageName,
            };

        }

        for (var j = 0; j < entries.length; j++) {

            var page = getThing(doc.pages, 'name', entries[j].pageName);

            if (!page)
                continue;

            // remove existing hyperlink
            var existing = text.findHyperlinks();
            for (var k = existing.length - 1; k >= 0; k--)
                existing[k].remove();

            var source = doc.hyperlinkTextSources.add(entries[j].text.characters.itemByRange(0, entries[j].text.length - 1)),
                destination = doc.hyperlinkPageDestinations.add(page, { hidden: true });

            // give the hyperlink a useful name
            var name = entries[j].text.paragraphs[0].words[0].contents,
                n = 0;

            // a name that won't conflict
            while (doc.hyperlinks.itemByName(name + ' ' + (++n)).isValid);

            // create the hyperlink and name it
            doc.hyperlinks.add(source, destination).name = name + ' ' + n;

            // apply the character style
            entries[j].text.applyCharacterStyle(characterStyle, true);

        }

    }

};
app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, 'Add Index Hyperinks');

/**
 * 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-04-28: Added ability to correctly match page number ranges, eg. 34-6 and ignore the second part.

Edit 2025-04-29: Added handling of en dash or hyphen between page numbers

Edit 2025-05-09: Fixed bug due to using a javascript regex in find grep, oops! Fixed bug due to using wrong code for endash. I must have been asleep! Added logic for "expanding" second number in page range so that 12–3 will create hyperlinks to pages 12 and 13 respectively.

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
New Here ,
Apr 28, 2025 Apr 28, 2025

Mark, this is so great, thank you so much! It's exactly what I needed! I'm going to experiment with it another time to see if I can get it working on page ranges (so 345-6 doesn't link as 345 and 6) but for now this will save me so much time. Thank you again!

Eubhal

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 ,
Apr 28, 2025 Apr 28, 2025

@Eubhal you're welcome. I've updated the script above so that it works with 345-6 ranges.

- Mark

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
New Here ,
Apr 29, 2025 Apr 29, 2025

Hi Mark,

 

No need to fix this if you'd rather not but I wanted to let you know that at present the updated script still seems to make the 6 just a link to page 6 rather than 346.

 

Thanks,

 

Eubhal

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 ,
Apr 29, 2025 Apr 29, 2025

We'll get there! Okay now I think it might be because the hyphen you used might be an endash (which it should be!)? In that case my script won't find it because it is looking for a hyphen. Sorry, that was lazy of me. I'll update the script above.

- Mark

 

P.S. if that wasn't the issue, please post a .indd document showing the situation.

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
New Here ,
Apr 29, 2025 Apr 29, 2025

No problem! Thanks so much for sticking with this! I'm afraid it now brings up the below error. I'm afraid it actually did this for the hyphen version too but I didn't realise.

Eubhal_0-1745917815889.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