Copy link to clipboard
Copied
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/
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
...
Copy link to clipboard
Copied
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
Copy link to clipboard
Copied
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
Copy link to clipboard
Copied
@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
Copy link to clipboard
Copied
I would just be finding them by hand and highlighting them
Copy link to clipboard
Copied
Copy link to clipboard
Copied
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? 😉
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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?
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
Okay got it, @Eubhal. Here's a script that might do what you want. Select the "index" text and run it.
- Mark
/**
* @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];
};
Copy link to clipboard
Copied
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?
Copy link to clipboard
Copied
Thanks Mark! This looks great but currently I'm getting this error message with it:
Copy link to clipboard
Copied
Thanks Mark! This looks great but currently I'm getting this error message with it:
By @Eubhal
Do you have hidden spreads in your document?
Copy link to clipboard
Copied
@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
Copy link to clipboard
Copied
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
Copy link to clipboard
Copied
Sorry, to be clear, I'd link a button to the script, I'm not asking you to find a button that does that!
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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
Copy link to clipboard
Copied
@Eubhal you're welcome. I've updated the script above so that it works with 345-6 ranges.
- Mark
Copy link to clipboard
Copied
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
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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.
Find more inspiration, events, and resources on the new Adobe Community
Explore Now