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

Web Link Buttons with Variable URLs

New Here ,
Apr 15, 2011 Apr 15, 2011

Copy link to clipboard

Copied

Hey all:

I asked my question earlier in the general InDesign section of the forum, but a helpful user suggested I repost it here as it will take some scripting magic to accomplish:

My work assignment of late has been developing an interactive PDF catalog of our products that my superior can distribute digitally and let potential customers browse without accessing the website.

We have an Excel file that lists all the details of our products - name, description, title, image, category, etc. I have used Data Merge to create this 300 page document rather than hand-copy each product's information to a single page.

Unfortunately I am now stuck - I have designed the catalog in such a way that I have an image that I want to make a button which, if the person wishes to purchase a product, will take them directly the the product page online where he or she can add it to the shopping cart. This is great, but I cannot seem to find a way to make the image button's link a variable as the rest of the page content. Links to each product page are included in the CSV file, but without a variable web link method, I would have to create the unique links individually, which kinda defeats the purpose of using Data Merge anyway.

So my question is this - is there any way to make a URL button (an image) have a web link function that can read from a CSV file and change each page like other imported content? If not, is there another way to automate the individual link process without setting it up on each generated page?

Thanks in advance,

Asher

TOPICS
Scripting

Views

3.0K

Translate

Translate

Report

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

LEGEND , Apr 20, 2011 Apr 20, 2011

If you were using the aformentioned code to check the script label, it would have to go inside the for (i) loop, replacing the "b = p.buttons[0]" line. Though there was a typo because I set t to the button and instead I should have set b to the button.

Yes, a group. If you know that there is only one group on the page, then you don't even have to loop over the groups. Instead you can just use:

t = p.groups[0].textFrames[0];

b = p.groups[0].buttons[0];

Of course, that'll break if there's ever more th

...

Votes

Translate

Translate
LEGEND ,
Apr 15, 2011 Apr 15, 2011

Copy link to clipboard

Copied

Hi, Asher.

You asked this question in the regular forum: Web Link Buttons with Variable URLs

and I gave you an initial answer in that forum:

var b, i, p, t,
    doc=app.activeDocument;
for (i=0; i<doc.pages.length; i++) {
    p = doc.pages;
    b = p.buttons[0];
    t = p.textFrames[0];
    b.gotoURLBehaviors.add({ url: t.contents });
}

How does it fail to meet your needs?

Votes

Translate

Translate

Report

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 20, 2011 Apr 20, 2011

Copy link to clipboard

Copied

Sorry for the late response. I am not really versed in Javascript and don't know exactly how to implement it. I copied the code into an ExtendScript window and it hung at the for loop, with the statusbar at the bottom saying "undefined is not an object."

In the original thread you stated that these lines of code would work only if there was one textbox and one button on each page - there are at least 12 other buttons and 8 other textboxes/frames.

Thanks for your help - this is really the last hurdle for this project to be finished.

Votes

Translate

Translate

Report

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 20, 2011 Apr 20, 2011

Copy link to clipboard

Copied

Did you tell the ESTK to run your script in InDesign, rather than the script editor itself?:

runswhere.png

Well, you if you have more than one text box on the page, how is each button supposed to know which text box to use for a URL? You'll have to come up with some scheme.

You can't expect the script to just read your mind...

Votes

Translate

Translate

Report

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 20, 2011 Apr 20, 2011

Copy link to clipboard

Copied

I'm running the script in a test document right now, which was generated with a small CSV file (holds the links) and has one text box which holds the link in text and one blank buttton per page. The document is four pages long, each with the generated set of objects.

I have the script set now, and it hangs at

b = p.buttons[0];

I'm new at this whole scripting thing, but would assigning them scripting labels help?

UPDATE:

I had a friend look it over and he changed the brackets to parenthases and added .item to the b and t - now the code works with one textbox/button a page.

var b, i, p, t,

    doc=app.activeDocument;

for (i=0; i<doc.pages.length; i++)

{

    p = doc.pages.item(i);

    b = p.buttons.item(0);

    t = p.textFrames.item(0);

    b.gotoURLBehaviors.add({ url: t.contents });

}

Votes

Translate

Translate

Report

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 20, 2011 Apr 20, 2011

Copy link to clipboard

Copied

Perhaps a screenshot of your page layout would help us to decide what the right way to handle this association is. Or perhaps someone else who actually uses these interactive features might chime in...

The script...should not hang. Does it give you an error? An orange bar on some line? If so, it should tell you the error in the bottom left corner of the window.

Not surprisingly, it works fine for me.

Script labels might help, yes! It sounds like you're not as new as you sound!

I'm not 100% how they'd interact with the data merge, but if there's only one button you need to fill in on each page [which is what it sounds like], then that should work fine. Alternatively, still if there's only one button, textFrames[0] should refer to the topmost ('Bring to Front') text frame. That might be a little fragile, but should probably work.

Oh, I see your update. I can...think of no reason why that should be necessary, and frankly I dislike using the .item(n) form because it's more typing and uglier. But whatever floats your boat. Are you sure there weren't any other changes?

Note that people who follow the forum via email won't see an update you add, so it's a good idea to make a new post if you have something significant to say...

Votes

Translate

Translate

Report

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 20, 2011 Apr 20, 2011

Copy link to clipboard

Copied

The new version my friend attended to works perfectly with the edits. As I mentioned in my last post the version you typed hangs (with the orange bar)at

b = p.buttons[0];

The console at the bottom line says "undefined is not an object"

I run the script after the data merge is complete, since there is only one layout page before executing it (as well as there not being any content).

I tried rearraging the button and text frame I want to target in the script just as you posted, and this works. But I agree, if there was a more direct way of doing it, I would prefer it.

I understand basic code purpose and structure, but I don't have much of a clue on how to write it from scratch haha. How would I call script labels to identify the two objects directly? My friend is helping me on this one as well, but he knows javascript outright, and does not use InDesign at all.

Thanks for the continuing help!

BTW, here is a screenshot of your version running with the error:

code2.JPG

Votes

Translate

Translate

Report

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 20, 2011 Apr 20, 2011

Copy link to clipboard

Copied

Huh, that error seems really mysterious. (I had assumed your initial problem was from targetting the ESTK instead of targetting ID, and when you said "hangs at the for loop" you meant the actual "for(..." line.) I'd be curious...if you run the broken version and after it hangs, try typing in the JavaScript console:

   p

   p.buttons

   p.buttons[0]

   p.item(0)

   p.buttons[0].id

   p.item(0).id

which ones work and which fail?

In CS5, script labels got a bit more annoying to use. I think you might be better off using text box names instead.

Name the text box in the Layers panel by click-pause-click-ing it (wow, what an unfamiliar UI!) and assigning a name to it.

Suppose you name it "url".

Then instead of "p.textFrames[0]" (or p.textFrames.item(0)), you can use "p.textFrames.itemByName('url')".

Hopefully this doesn't get messed up across the data merge.

To use the script label, you need this horrid construction:

var j;

for (j=0; j<p.textFrames.length; j++) {

    if (p.textFrames.label === 'url') {

        t = p.textFrames;

        break;

    }

}

though if your InDesign is screwed up, you might need to change -> item(j) again. Maybe you should Replace Your Preferences (http://forums.adobe.com/thread/526990).

Votes

Translate

Translate

Report

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 20, 2011 Apr 20, 2011

Copy link to clipboard

Copied

I am back home from work, but I Dropboxed the jsx file so I could tinker with it here. I recreated my test file (3 buttons - one used, three textboxes - one with the link) and tried your code again. Suddenly, it works! Both your code and my friend's variant worked. Soe something must be strange in the settings of InDesign at work.

I added the name-specific code to the file and it worked through the first iteration of the loop, but stopped short. I named the text frame 'url' and the button 'urlbutton' - the problem is, buttons apparently need specific identifiers in the layers, and after a data merge (I have three links in the csv file, so it generates three pages and three sets of everything) the buttons add numbers to the layer name, so the code breaks. Naming and calling the text frame in the code allows it to find the right URL regardless of the layer order, but it unless there is another way to call the button regardless of its layer name, the button will have to be first.

On the other hand, Script Labels are constant no matter how many copies there seem to be. Assigning the original urlbutton with "urlbutton" as a label will give the three generated buttons "urlbutton" as a label, unchanged. So unless there's another way (besides putting it as first button in layer order), I'd have to use the script label to identify the right button?

Votes

Translate

Translate

Report

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 20, 2011 Apr 20, 2011

Copy link to clipboard

Copied

Yeah, I think something was screwed up with your work machine, hence the suggestion to replace your preferences.

I was afraid the naming might break. So you get to use the more complicated script code. Oh well. This is an annoyance a lot of people have with CS5, because prior to CS5, the syntax for finding items by label was the syntax we now use to find by name.

There are lots of other ways, but the Script Label is probably best. You could depend on the z-ordering. You should search for a text frame that contains "http://". You could search for a textframe that contains "zaphod breeblebrox" and take the third word. You could find the textframe in a particular position on the page. Or containing a specific paragraph style. Or hundreds of other choices.

Votes

Translate

Translate

Report

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 20, 2011 Apr 20, 2011

Copy link to clipboard

Copied

So would the button version of the code you posted be this? And I'm assuming it'd go before the original part?

var j;

for (j=0; j<p.buttons.length; j++) {

    if (p.buttons.label === 'urlbutton') {

        t = p.buttons;

        break;

    }

}

Votes

Translate

Translate

Report

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 20, 2011 Apr 20, 2011

Copy link to clipboard

Copied

If you were using the aformentioned code to check the script label, it would have to go inside the for (i) loop, replacing the "b = p.buttons[0]" line. Though there was a typo because I set t to the button and instead I should have set b to the button.

Yes, a group. If you know that there is only one group on the page, then you don't even have to loop over the groups. Instead you can just use:

t = p.groups[0].textFrames[0];

b = p.groups[0].buttons[0];

Of course, that'll break if there's ever more than one group.

Votes

Translate

Translate

Report

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 20, 2011 Apr 20, 2011

Copy link to clipboard

Copied

I think we have a winner! I tried the group at the top of the layer list, somewhere in the middle, and at the bottom in a whole new layer, and running the script successfully transferred the link codes to the URL of the button.

I remember you put at the bottom of one of your posts in the original thread that there was a way to delete the text frame. How would I implement that in the script, and would it be affected by the grouping?

Votes

Translate

Translate

Report

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 20, 2011 Apr 20, 2011

Copy link to clipboard

Copied

Sure. The answer there is the same as the answer now

Just add t.remove() at the end of the loop. Of course that has to be after you use t.contents, so after you set the gotoURLBehaviors.

Votes

Translate

Translate

Report

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 20, 2011 Apr 20, 2011

Copy link to clipboard

Copied

So just for clarification for anyone else, here's the workflow:

1. Design layout

2. Use Data Merge to import information and assign the frames the data variables

3. Create button and group it with the link text frame

4. Run the data merge to create the pages

5. Open/run the script, which takes the now-filled-in link text frame's content and transplants it in the URL line of the buttons. The script also deletes the link text frames

6. Export as an interactive PDF

7. Enjoy your variable buttons!

Final JS code:

var b, i, p, t,
    doc=app.activeDocument;
for (i=0; i<doc.pages.length; i++) {
    p = doc.pages;
    b = p.groups[0].buttons[0];
    t = p.groups[0].textFrames[0];
    b.gotoURLBehaviors.add({ url: t.contents });
    t.remove()
}

This works if you are using a single group - that of the button object and the link text frame.

Votes

Translate

Translate

Report

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 ,
Mar 12, 2021 Mar 12, 2021

Copy link to clipboard

Copied

Hello,

Thank you for sharing here these highly valuable outcomes and ressources. I'm glad that I can find some support on that specific point. I'm getting through the same kind of need: Web Link Buttons with Variable URLs from a csv data base. I've implemented everything you recommanded here, but unfortunately InDesign seems not to run the .jsx file properly. Here is the message I get while running the script : "Object does not support the property or method 'groups' ".

We are now in 2021, I am working with Indesign 16. Would this explains why I'm facing such an issue?

Many thanks in advance for your insights.

Votes

Translate

Translate

Report

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 20, 2011 Apr 20, 2011

Copy link to clipboard

Copied

Oh, sorry, I wasn't paying attention to the fact that you needed to

identify the buttons as well as the text frames. Though since buttons

do have names I suppose you could use a variant.

Another good approach would be to put each button and textframe pair

in a group. Then you can iterate over the groups on the page and

take group.button[0] and group.textFrame[0] in each case.

I think that might be the cleanest answer.

Votes

Translate

Translate

Report

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 20, 2011 Apr 20, 2011

Copy link to clipboard

Copied

Whoops, didn't refresh the page.

A group you say? So the code would only look for available groups on each page, and since there would be only one - containing the text frame and the button - it'd automatically single them out? That sounds great!

Votes

Translate

Translate

Report

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 19, 2021 Apr 19, 2021

Copy link to clipboard

Copied

JCD-5DC5 said at Mar 12, 2021:
"I've implemented everything you recommanded here, but unfortunately InDesign seems not to run the .jsx file properly. Here is the message I get while running the script : "Object does not support the property or method 'groups' ".

We are now in 2021, I am working with Indesign 16. Would this explains why I'm facing such an issue?"

 

No, that does not explain it. It's way more trivial. In late 2019 this thread was moved from the old forum to the new InDesign forum. And by that all that code was damaged. A bug with moving threads with code around. Happened to a lot of threads that were done before October 2019.

 

Could you please post the ExendScript code you tested?

I think I will be able to fix it.

 

Thanks,
Uwe Laubender

( ACP )

Votes

Translate

Translate

Report

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 20, 2021 Apr 20, 2021

Copy link to clipboard

Copied

Hello Uwe,

Thank you for getting back to me. 

Actually, I implemented exactly the process carefuly detailed in this thread.

See bellow the JS Code used:

 

var b, i, p, t,
    doc=app.activeDocument;
for (i=0; i<doc.pages.length; i++) {
    p = doc.pages;
    b = p.groups[0].buttons[0];
    t = p.groups[0].textFrames[0];
    b.gotoURLBehaviors.add({ url: t.contents });
    t.remove()
}
 
As I'm a beginer in scripting, there is certainly a mistake I wasn't able to spot on.
Many thanks for your support and suggestions.

Votes

Translate

Translate

Report

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 20, 2021 Apr 20, 2021

Copy link to clipboard

Copied

I cannot edit John's post so here the fixed code:

var b, i, p, t,
	doc=app.activeDocument;
for (i=0; i<doc.pages.length; i++)
{
	p = doc.pages[i];
	b = p.groups[0].buttons[0];
	t = p.groups[0].textFrames[0];
	b.gotoURLBehaviors.add({ url: t.contents });
	t.remove();
};

The one thing that was dropped by moving the code over to the new forum was iterator [i] inside the for-loop. This is a common issue with old threads showing code. So before it was: p = doc.pages which makes no sense, because it addresses the collection of all document pages in a document and not a specific page.

 

Now I changed that to p = doc.pages[i] so that with every turn of the loop a different page is addressed starting with psges[0], the first page* and goes on adding 1 to that iterator i until condition i<doc.pages.length is not met anymore. pages.length is the total amount of document pages, a number, in the document that's behind variable doc. i++ is the short form of i = i+1 and dictates the steps the iterator will take with every loop.

 

*ExtendScript is starting to count with 0 and not with 1.

 

Some annotations:

The code above is not testing if there is a group on the page. And it also does not test if the group contains a button and a text frame. It simply assumes that. This could lead to errors on pages that do not meet that minimum requirement. Also note, that the text frame in that group will be removed after the behavior was added to the button. That would leave you with a group of 1 element, the button, if your initial group has only two elements, the button and the textframe.

 

Regards,
Uwe Laubender

( ACP )

Votes

Translate

Translate

Report

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 ,
Aug 02, 2021 Aug 02, 2021

Copy link to clipboard

Copied

Hi,

 

I'm actually a noob at scripting. Thanks to this thread I’m so close to an (almost) fully automated work process. Thanks everyone!

 

I almost got this working, but the script skips a lot of groups. When the script runs, it usually transforms just one group (button + textframe) into a URL button and gives me an error. It leaves all other groups untouched. Re-running the script won't help.

 

It's probably because my document has multiple pages without groups and some pages with 2 groups.

If I test this script with one group on each page, it works fine. But I need 2 URL buttons on 1 page (greedy, I know).

It also seems the script will stop working if it encounters a page without a group. All groups on pages after that will not turn into URL buttons.

 

As mentioned, the above code does not "test" whether there is a group (or page) that meets all requirements.

And this code is probably only useful for one group per page.

 

Is there a way to change the code to check for multiple groups on one page? And also that it only targets pages that meet the requirements.

 

((For now, I'll put "dummy groups" on each page, on a different layer. After I run the script, I just delete the layer. Since I need 2 URL buttons on 1 page, I slide the second URL button from another page to its final position. I have to do that for 100+ pages. It's not ideal, but it's better than setting 200+ URL buttons by copying and pasting manually. ))

 

Thanks in advance! 😊

Votes

Translate

Translate

Report

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 ,
Dec 21, 2022 Dec 21, 2022

Copy link to clipboard

Copied

Hoping for help on this- I'm using the above script in the most recent updated of indesign 2023 and am getting the following error: 

defaultqhmzc0ocxp38_0-1671633669771.png

Using this script:

var b, i, p, t,
doc=app.activeDocument;
for (i=0; i<doc.pages.length; i++)
{
p = doc.pages[i];
b = p.groups[0].buttons[0];
t = p.groups[0].textFrames[0];
b.gotoURLBehaviors.add({ url: t.contents });
t.remove();
};

 

All help appreciated!

Thanks Elisha

Votes

Translate

Translate

Report

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 ,
Mar 10, 2023 Mar 10, 2023

Copy link to clipboard

Copied

I would like to use this script and it seems as though I am in the same delima as Asher so I need to know where I can find this script please? I would like to be sure it's what I am looking for, can you help?

 

Votes

Translate

Translate

Report

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 ,
Mar 13, 2023 Mar 13, 2023

Copy link to clipboard

Copied

LATEST

Hi @Toni Rae ,

read my reply above where I did repost the code.

And also read my annotations carefully.

 

Regards,
Uwe Laubender
( Adobe Community Expert )

Votes

Translate

Translate

Report

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