Forum Moderators: open

Message Too Old, No Replies

How to remove multiple onclick events?

Simplifying overheavy inline Javascript

         

encyclo

7:32 pm on Sep 25, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



I have a photo gallery which uses a ton of repetition and inline Javascript
onclick
events to make a user-generated popup when clicking on a thumbnail. Currently I have this (radically simplified for clarity, in reality it's a lot worse):

<div class="photohold">
<ol class="phindex">
<li><a href="/photos/s01.php" [b]onclick="ouvreMoi('/photos/s01.php','s01');return false;"[/b]><img src="/photos/s-050902-1.jpg" width="57" height="75" alt=""></a></li>
<li><a href="/photos/s02.php" [b]onclick="ouvreMoi('/photos/s02.php','s02');return false;"[/b]><img src="/photos/s-050805-1.jpg" width="76" height="75" alt=""></a></li>
<li><a href="/photos/s03.php" [b]onclick="ouvreMoi('/photos/s03.php','s03');return false;"[/b]><img src="/photos/s-050903-1.jpg" width="84" height="75" alt=""></a></li>
</ol>
</div>

With the following very simple Javascript:

function ouvreMoi(theURL,winName){
newWindow = window.open(theURL,winName,'top=20,left=15,scrollbars=yes,resizable=yes,width=700,height=565');
}

Rather than having to repeat everything, I would like the markup to resemble this::

<div class="photohold">
<ol class="phindex">
<li><a href="/photos/s01.php"><img src="/photos/s-050902-1.jpg" width="57" height="75" alt=""></a></li>
<li><a href="/photos/s02.php"><img src="/photos/s-050805-1.jpg" width="76" height="75" alt=""></a></li>
<li><a href="/photos/s03.php"><img src="/photos/s-050903-1.jpg" width="84" height="75" alt=""></a></li>
</ol>
</div>

ie. with no

onclick
at all. As you can see, the thumbnails are in an unordered list within a
div
- each with a specific
id
or
class
which is only used for the section where I need the popups to appear.

My question is this: is it possible with Javascript to target the links within a specific

id
or
class
and make them generate a popup without having to have all the redundant inline scripting?

Bernard Marx

8:28 pm on Sep 25, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Yes, it is.

This one will attach the function below as the onclick method to all <a> tags that are within any <div class="photohold"> in the document.

The className is tested by a regular expression, so a className like "doo photohold" will also be accepted.

The script checks all the document's DIVs for the className. If there are many divs of all kinds, it may be worth targeting a common parent (if there is one) for efficiency.

There is enough info in the link's href to use for the opening function.

onload = function()
{
var regTargetClass = /\bphotohold\b/;
var divs = document.getElementsByTagName('div');

// loop divs
for(var i=0, div; div=divs[i++];)
{
// reject non-photohold divs
if(! regTargetClass.test(div.className) ) continue;
// attach onclick event to each <a>
var links = div.getElementsByTagName('a');
for(var j=0, link; links=links[j++];)
links.onclick = ouvreMoi;
}

}

//!: Corrupted pipe char, ¦, will need to be replaced with a proper one.

function ouvreMoi()
{
newWindow = window.open(
this.href,
this.href.replace(/^.*\/¦\.[^\.]*$/g, ''), // #1
'top=20,left=15,scrollbars=yes,resizable=yes,width=700,height=565'
);
}

Bernard Marx

9:12 pm on Sep 25, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



<edited: 21:25 GMT>

#2 is the "usual approach". I'm trying to convince Rambo Tribble of the merits of an approach that I'm championing. There's no need for the script to go round adding event handlers all over the place, which could take time.


document.onclick = function(e)
{
var elm = getEventSrc(e);
// filter clicks from images that are
// descendants of elms with class, "photohold"
if( elm.tagName.toUpperCase = 'IMG'
&& getAncestor(elm.parentNode, 'className',/\bphotohold\b/)
){
ouvreMoi(elm.parentNode);
preventDefault(e); // stop href being followed.
}
}

function ouvreMoi(link)
{
newWindow = window.open(
link.href,
link.href.replace(/^.*\/¦\.[^\.]*$/g, ''),
'top=20,left=15,scrollbars=yes,resizable=yes,width=700,height=565'
);
}

//---------------------------------------------------------
// Utilities used
//---------------------------------------------------------

function preventDefault(e)
{
e? e.preventDefault() : event.returnValue = false;
}

function getEventSrc(e)
{
var targ = (e¦¦event).target;
if(targ)
return targ.nodeType==1?targ:targ.parentNode
else
return event.srcElement;

}

function getAncestor(elm,prop,regVal)
{
while(elm)
{
if(regVal.test(elm[prop])) return elm;
elm = elm.parentNode;
}
}

//---------------------------------------------------------

[edited by: jatar_k at 3:34 pm (utc) on Oct. 5, 2005]
[edit reason] remove old url [/edit]

encyclo

1:03 am on Sep 26, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Thanks BM with your informative answers (as always!). I'm not clear which one you are recommending, though. On my particular site, the popup links are solely contained within the double div/ol as shown above - would the first script be heavier or slower as it has to check every tag, or is there no real-world difference? The script will be called on every page of the site irrespective of whether there is a thumbnail block (although I can change that if need be).

Bernard Marx

8:00 am on Sep 26, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



//---------------------------------------------------------
I introduced some typos in the first script.
Here's the onload function again
(and let's see if we can get the post editor to behave)


onload = function()
{
var regTargetClass = /\bphotohold\b/;
var divs = document.getElementsByTagName('div');
// loop divs
for(var i=0, div; div=divs[i++];)
{
// reject non-photohold divs
if(! regTargetClass.test(div.className) ) continue;
// attach onclick event to each <a>
var links = div.getElementsByTagName('a');
for(var j=0, link; link=links[j++];)
link.onclick = ouvreMoi;
}
}

//---------------------------------------------------------

I'm not clear which one you are recommending

Nor am I, encyclo!

The first one pretty much standard fare, and won't confuse anybody.
The second is more experimental. I think it's better, but I don't want to be responsible for leading you down the garden path.

The drawbacks of the first are (these are commonly discussed issues)

1) The initialising process cannot be done until after the link elements themselves have loaded. Using the onload event as a trigger will mean that thisprocess doesn't even start until all images have loaded, which could possibly be a few seconds.

Only IE has a document.onContentReady event, so the only sensible cross-browser work-around is to place a small script block, containing a call to the initialising function, at the bottom of the document. Some people feel uncomfortable will this, but Tribble says that Snoop Dogg told him it's OK.

2) When the initialisiation is triggered, if there's a lot of event handler attachment to do, this can also take time.

The event handlers are 'manually' attached to all the links and, before that, all the documents DIVs need to be checked. Not a big deal in all but the most DIV-heavy documents, but you may still notice a little iniation delay.

The second script only needs an event handler on the document. This can be done immediately (since the document always exists).

Yet, if you're not in the mood for the BM adventure of script 2, script 1 can be improved.

I understood (or at least, allowed for) the possibility that there might be more than one "photohold" DIV in a document. If, in fact, there will only ever be one of these, then the efficiency can be improved by targetting it directly. To do this, the div will need an id instead of, or as well as, a className.

If there is just one div, with an id (say, "photoholder"). The onload function can be simply.

onload = function() 
{
var links = document.getElementById('photoholder')
.getElementsByTagName('a');

for(var k=0, link; link=links[k++];)
link.onclick = ouvreMoi;

}

Bernard Marx

5:17 pm on Sep 26, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Sorry. If there isn't always such a div, then we should check first:

onload = function() 
{
var holder = document.getElementById('photoholder');
if(!holder) return;
var links = holder.getElementsByTagName('a');
for(var k=0, link; link=links[k++];)
link.onclick = ouvreMoi;
}