//MakeHyperlinks_CS2.jsx
//An InDesign CS2 JavaScript
//
//Finds a string in text and creates a hyperlink based on the
//contents of the string. This script employs a hybrid approach to
//finding and changing text, using both JavaScript regular expressions
//and InDesign's search method.
//
main();
function main(){
if(app.documents.length != 0){
if(app.documents.item(0).stories.length != 0){
//Construct regular expression to find hyperlink sources.
//The following RegExp should find all URLs in text.
var myRegExp = /\b(https?|ftp|file):\/\/[-A-Za-z0-9+&@#\/%?=~_|!:,.;]*[-A-Za-z0-9+&@#\/%=~_|]/gi;
var myURLPrefix = "";
var myURLSuffix = ""
mySearchStories(myRegExp, myURLPrefix, myURLSuffix);
//Next, do it again to find the GAO-specific documents.
myRegExp = /GAO(-|\/)[\d]*-[\d]*/gi;
myURLPrefix = "http:\/\/www.gao.gov\/cgi-bin\/getrpt?";
myURLSuffix = ".html"
mySearchStories(myRegExp, myURLPrefix, myURLSuffix);
//Finally, catch the email addresses and convert to mailto links.
myRegExp = /\b[A-Za-z0-9._%-]+@(?:[A-Za-z0-9-]+\.)+[A-Za-z]{2,4}\b/gi
myURLPrefix = "mailto:";
myURLSuffix = ""
mySearchStories(myRegExp, myURLPrefix, myURLSuffix);
}
else{
alert("The current document does not contain any text.");
}
}
else{
alert("Please open a document and try again.");
}
alert("Done!");
}
function mySearchStories(myRegExp, myURLPrefix, myURLSuffix){
var myStory, myStoryText, myFoundItems, myFoundStrings, myHyperlinkDestination, myFootnoteCounter;
var myStart, myEnd, myFootnote, myStringCounter, myFoundItem, myTableCounter, myCellCounter, myTable, myCell;
var myHyperlinkTextSource, myTextCounter, myStringCounter;
var myFoundStrings = new Array;
var myDocument = app.documents.item(0);
var myHyperlinkStyle = myDocument.characterStyles.item("hyperlink text");
for(var myCounter = 0; myCounter < myDocument.stories.length; myCounter ++){
//Get the text of the story as a string.
myStory = myDocument.stories.item(myCounter);
if(myStory.characters.length > 1){
myStoryText = myStory.contents;
//If the story contains only a special character (such as an auto page number marker),
//the following will fail, so use try...catch to avoid the problem.
try{
if(myStoryText.match(myRegExp)!=null){
myFoundStrings = myFoundStrings.concat(myStoryText.match(myRegExp));
}
}
catch (myError){}
}
//The text of tables in the story will not appear in myStory.contents, so
//we need to search the text of each story. There's always the possibility that
//the cells contain tables of their own, but this script won't check for that possibility.
if(myStory.tables.length != 0){
for(myTableCounter = 0; myTableCounter < myStory.tables.length; myTableCounter++){
myTable = myStory.tables.item(myTableCounter);
for(myCellCounter = 0; myCellCounter < myTable.cells.length; myCellCounter++){
myCell = myTable.cells.item(myCellCounter);
//Does the cell contain any text? If it does, the length of the
//insertion points collection will be greater than 1.
if(myCell.insertionPoints.length > 1){
myCellText = myCell.texts.item(0).contents;
if(myCellText.match(myRegExp)!= null){
myFoundStrings = myFoundStrings.concat(myCell.texts.item(0).contents.match(myRegExp));
}
}
}
}
}
}
if(myFoundStrings.length > 0){
myFoundStrings = myRemoveDuplicates(myFoundStrings);
//Search through the sorted strings in reverse order--that way, you'll catch the longer URLs
//before the base URLs (e.g., http://www.adobe.com *after* http://www.adobe.com/products).
for(myStringCounter = myFoundStrings.length-1; myStringCounter >= 0; myStringCounter--){
myClearFindChange();
myFoundItems = myDocument.search(myFoundStrings[myStringCounter]);
if(myFoundItems.length != 0){
myHyperlinkDestination = myMakeURLHyperlinkDestination(myURLPrefix + myFoundStrings[myStringCounter] + myURLSuffix);
for(myTextCounter = 0; myTextCounter < myFoundItems.length; myTextCounter++){
myFoundItem = myFoundItems[myTextCounter];
myMakeHyperlink(myFoundItem, myHyperlinkDestination, myHyperlinkStyle);
}
}
myClearFindChange();
}
}
myFoundString = new Array;
//Handle the footnotes here.
//Iterate through the stories again.
for(var myCounter = 0; myCounter < myDocument.stories.length; myCounter ++){
myStory = myDocument.stories.item(myCounter);
if(myStory.footnotes.length > 0){
for(myFootnoteCounter = 0; myFootnoteCounter < myStory.footnotes.length; myFootnoteCounter++){
myFootnote = myStory.footnotes.item(myFootnoteCounter);
myStoryText = myFootnote.texts.item(0).contents;
try{
if(myStoryText.match(myRegExp)!=null){
myFoundStrings = myStoryText.match(myRegExp);
//Found at least one matching string in the footnote, so use
//itemByRange to construct a text object, then use that object to
//create a hyperlink text source.
for(myStringCounter = 0; myStringCounter < myFoundStrings.length; myStringCounter++){
myFoundString = myFoundStrings[myStringCounter];
myStart = myStoryText.indexOf(myFoundString);
myEnd = myStart + myFoundString.length-1;
myFoundItem = myFootnote.texts.itemByRange(myFootnote.characters.item(myStart), myFootnote.characters.item(myEnd));
myHyperlinkDestination = myMakeURLHyperlinkDestination(myURLPrefix + myFoundString + myURLSuffix);
myMakeHyperlink(myFoundItem, myHyperlinkDestination, myHyperlinkStyle);
}
}
}
catch (myError){}
}
}
}
}
function myMakeHyperlink(myFoundItem, myHyperlinkDestination, myHyperlinkStyle){
var myDocument = app.documents.item(0);
try{
var myHyperlinkTextSource = myDocument.hyperlinkTextSources.add(myFoundItem);
var myHyperlink = myDocument.hyperlinks.add(myHyperlinkTextSource, myHyperlinkDestination);
//Hyperlink and text formatting attributes.
myFoundItem.applyStyle(myHyperlinkStyle, false);
myHyperlink.visible = false;
}
catch(myError){}
}
function myMakeURLHyperlinkDestination(myURL){
var myDocument = app.documents.item(0);
//If the hyperlink destination already exists, use it;
//if it doesn't, then create it.
try{
var myHyperlinkDestination = myDocument.hyperlinkURLDestinations.item(myURL);
myHyperlinkDestination.name;
}
catch(myError){
myHyperlinkDestination = myDocument.hyperlinkURLDestinations.add(myURL);
}
myHyperlinkDestination.name = myURL;
//Set other hyperlink properties here, if necessary.
return myHyperlinkDestination;
}
function myRemoveDuplicates(myArray){
//Semi-clever method of removing duplicate array items; much faster
//than comparing every item to every other item!
var myNewArray = new Array;
myArray = myArray.sort();
myNewArray.push(myArray[0]);
if(myArray.length > 1){
for(var myCounter = 1; myCounter < myArray.length; myCounter ++){
if(myArray[myCounter] != myNewArray[myNewArray.length -1]){
myNewArray.push(myArray[myCounter]);
}
}
}
return myNewArray;
}
function myClearFindChange(){
app.findPreferences = NothingEnum.nothing;
app.findPreferences = NothingEnum.nothing;
}