Modifying A tag onclick events dynamically - am I crazy

G

GaryB

Hi Guys,

I've been battling with this one for hours - I hope that you can help
me!

My code modifies the <a> on a page, from a standard document link into
a link with a tailored onclick event.

It works perfectly (assigning the correct images and the correct
onclick events to the correct <a> tags):
(a) If there's only one link on the page and
(b) If I modify the <a> tags one at a time - hardcoding (if there's
more than one link on the page).

However, if there's more than one link on the page, my code assigns
each onclick event to all of the previous nodes in the array instead of
each one independently. (I've commented the problematic line of
javascript, with "THIS IS THE PROBLEM LINE"). I must be missing
something!

Here's a page with the code (including a dummy loadDoc function). It
should show the problem as is (the images obviously won't show):

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Modify A Links</title>
<link href="ProdsolEpd.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="ProdsolEpd.js"></script>
<script language="JavaScript" type="text/javascript">
function ModifyLinks()
{
//Create Document links
var docArray = document.getElementsByTagName('font');
var sourceHTML, sourceHref, path, doc, ext, img, docName, fontNode,
linkNode, imageNode;
for(var d=0;d<docArray.length;d++)
{
if(docArray[d].className=='doc')
{
//Get values
fontNode = docArray[d];
sourceHTML = fontNode.innerHTML;
sourceHref=(sourceHTML.substring(sourceHTML.indexOf('"')+1,sourceHTML.indexOf('">')));
path = sourceHref.substring(sourceHref.indexOf('/',8));
doc = path.substring(path.lastIndexOf('/')+1);
ext = doc.substr(doc.length - 3);
docName = fontNode.innerText;
//Determine image
switch(sourceHTML.substr(sourceHTML.indexOf('>')-4,3))
{
case 'doc' : img="msword.png"; break;
case 'xls' : img="msexcel.png"; break;
case 'ppt' : img="mspowerpoint.png"; break;
case 'pdf' : img="pdf.png"; break;
}
linkNode = fontNode.children(0);
linkNode.setAttribute('href','#');
imageNode =
linkNode.insertBefore(document.createElement('img'),linkNode.firstChild);
imageNode.src = 'Skins/Standard/'+img;
imageNode.alt = docName;
linkNode.onclick = function(){loadDoc(sourceHref)};//THIS IS THE
PROBLEM LINE
}
}
}
function loadDoc(filespec)
{
//Dummy code to test the onclick event coding
alert(filespec);
}
window.onload = ModifyLinks;
//-->
</script>
</head>

<body>
<h3>Dynamically Modifying A Tags</h3>

<font class='doc'><a
href="http://localhost:1411/UserData/Test1.doc">Document
1</a></font><br />
<font class='doc'><a
href="http://localhost:1411/UserData/Test1.xls">Spreadsheet
1</a></font><br />
<font class='doc'><a
href="http://localhost:1411/UserData/Test1.ppt">Presentation
1</a></font><br />
<font class='doc'><a
href="http://localhost:1411/UserData/Test2.doc">Document
2</a></font><br />

</body>
</html>

I'd be very grateful for your help - can't figure it out!

Thanks very much.

Regards

Gary

gb at prodsol dot co dot nz
 
B

bobzimuta

GaryB wrote:
However, if there's more than one link on the page, my code assigns
each onclick event to all of the previous nodes in the array instead of
each one independently. (I've commented the problematic line of
javascript, with "THIS IS THE PROBLEM LINE"). I must be missing
something!
for(var d=0;d<docArray.length;d++)
{
if(docArray[d].className=='doc')
{
//Get values
fontNode = docArray[d];
sourceHTML = fontNode.innerHTML;
sourceHref=(sourceHTML.substring(sourceHTML.indexOf('"')+1,sourceHTML.indexOf('">')));

To get the 'href' of the anchor tag I'd suggest using
var anchor = fontNode.getElementsByTagName( 'A' )[0];
var href = anchor.href;
path = sourceHref.substring(sourceHref.indexOf('/',8));
doc = path.substring(path.lastIndexOf('/')+1);
ext = doc.substr(doc.length - 3);
docName = fontNode.innerText;
//Determine image
switch(sourceHTML.substr(sourceHTML.indexOf('>')-4,3))
{
case 'doc' : img="msword.png"; break;
case 'xls' : img="msexcel.png"; break;
case 'ppt' : img="mspowerpoint.png"; break;
case 'pdf' : img="pdf.png"; break;
}
linkNode = fontNode.children(0);

Again,
linkNode = fontNode.getElementsByTagName( 'A' )[0];
if you had a space like this ( underscore representing space )
<font>_<a..>
children(0) == ' ' .. At least that's how it is using DOM childNodes
array
linkNode.setAttribute('href','#');

Don't remove the href
imageNode =
linkNode.insertBefore(document.createElement('img'),linkNode.firstChild);
imageNode.src = 'Skins/Standard/'+img;
imageNode.alt = docName;
linkNode.onclick = function(){loadDoc(sourceHref)};//THIS IS THE
PROBLEM LINE
}

linkNode.onclick = function() { loadDoc( this.href ); return false };
the return false; statement prevents the browser from taking the
default action, which is to follow the link
 
R

RobG

GaryB said:
Hi Guys,

I've been battling with this one for hours - I hope that you can help
me!

My code modifies the <a> on a page, from a standard document link into
a link with a tailored onclick event.

It works perfectly (assigning the correct images and the correct
onclick events to the correct <a> tags):
(a) If there's only one link on the page and
(b) If I modify the <a> tags one at a time - hardcoding (if there's
more than one link on the page).

However, if there's more than one link on the page, my code assigns
each onclick event to all of the previous nodes in the array instead of
each one independently. (I've commented the problematic line of
javascript, with "THIS IS THE PROBLEM LINE"). I must be missing
something!

Here's a page with the code (including a dummy loadDoc function). It
should show the problem as is (the images obviously won't show):

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

Consider moving into the 21st century and use 4.01 strict.


[...]
<script language="JavaScript" type="text/javascript">

The language attribute has been deprecated for many years, you can
remove it.

function ModifyLinks()
{
//Create Document links
var docArray = document.getElementsByTagName('font');

Consider replacing the deprecated font elements with spans - but in any
case, the document.links collection gives you all the links (A
elements) anyway.

Please don't use tabs, use 2 or 4 spaces for indenting posted code and
wrap it at about 70 characters to prevent auto-wrapping (which
invariably introduces more errors).

var sourceHTML, sourceHref, path, doc, ext, img, docName, fontNode,
linkNode, imageNode;
for(var d=0;d<docArray.length;d++)

You could use the links collection here:

var link, links = document.links;
for (var i=0, len=links.length; i++){
link = links;
{
if(docArray[d].className=='doc')

It may be better to test if 'doc' is one of the class names, rather
than the only class name. Elements can have multiple CSS classes
assigned to them.

{
//Get values
fontNode = docArray[d];
sourceHTML = fontNode.innerHTML;
sourceHref=(sourceHTML.substring(sourceHTML.indexOf('"')+1,sourceHTML.indexOf('">')));

That is a very convoluted way to get the href value. Using the links
collection:

sourceHref = link.href;

path = sourceHref.substring(sourceHref.indexOf('/',8));
doc = path.substring(path.lastIndexOf('/')+1);
ext = doc.substr(doc.length - 3);
docName = fontNode.innerText;

innerText is an IE proprietary property, it is not well supported by
other browsers. The W3C equivalent is textContent, search the archives
for cross browser solutions - but it isn't needed here anyway. All you
seem interested in is the extension:

var ext = sourceHref.substr(sourceHref.length - 3);

//Determine image
switch(sourceHTML.substr(sourceHTML.indexOf('>')-4,3))

Didn't you already put the extension into 'ext'?

{
case 'doc' : img="msword.png"; break;
case 'xls' : img="msexcel.png"; break;
case 'ppt' : img="mspowerpoint.png"; break;
case 'pdf' : img="pdf.png"; break;
}

You could also do that with an object:

var extObj = {
doc : 'msword.png',
xls : 'msexcel.png',
ppt : 'mspowerpoint.png',
pdf : 'pdf.png'
}
img = extObj[ext];

linkNode = fontNode.children(0);
linkNode.setAttribute('href','#');

Why didn't you do that to get the link in the first place, instead of
innerHTML? Anyhow, now you already have a reference to the link:

link.href = '#';

imageNode =
linkNode.insertBefore(document.createElement('img'),linkNode.firstChild);
imageNode.src = 'Skins/Standard/'+img;
imageNode.alt = docName;
linkNode.onclick = function(){loadDoc(sourceHref)};//THIS IS THE
PROBLEM LINE

You are creating a closure back to the local variable sourceHref. Each
onclick event is passed the same value, which is whatever value
sourceHref had when the function exited.

Search the archives for fixes. The simplest (though maybe not 'best'),
given that sourceHref is a string, is to use another small function to
add the onclick, something like:

...
addOnclick(linkNode, loadDoc, sourceHref);
...

function addOnclick(obj, func, parm){
obj.onclick = function(){func(parm);}
}


It seems a complete waste of time to replace a perfectly good href with
an onclick that is problematic. Why not just add the images/icons and
leave well enough alone?

}
}
}
function loadDoc(filespec)
{
//Dummy code to test the onclick event coding
alert(filespec);
}
window.onload = ModifyLinks;
//-->

Do not use HTML comment delimiters inside script elements - they are
completely unnecessary and may cause problems (but the one above
doesn't, it is interpreted as a comment line and is ignored).
</script>
</head>

<body>
<h3>Dynamically Modifying A Tags</h3>

<font class='doc'><a
href="http://localhost:1411/UserData/Test1.doc">Document
1</a></font><br />

Do not use XHTML syntax in an HTML document - the browser is quite
within its rights to display the closing '>' (but probably wont). It
is also invalid HTML to put an A element inside a FONT element.


[...]
 
D

darwinist

GaryB said:
Hi Guys,

I've been battling with this one for hours - I hope that you can help
me!

My code modifies the <a> on a page, from a standard document link into
a link with a tailored onclick event.

It works perfectly (assigning the correct images and the correct
onclick events to the correct <a> tags):
(a) If there's only one link on the page and
(b) If I modify the <a> tags one at a time - hardcoding (if there's
more than one link on the page).

However, if there's more than one link on the page, my code assigns
each onclick event to all of the previous nodes in the array instead of
each one independently. (I've commented the problematic line of
javascript, with "THIS IS THE PROBLEM LINE"). I must be missing
something!

Here's a page with the code (including a dummy loadDoc function). It
should show the problem as is (the images obviously won't show):

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Modify A Links</title>
<link href="ProdsolEpd.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="ProdsolEpd.js"></script>
<script language="JavaScript" type="text/javascript">
function ModifyLinks()
{
//Create Document links
var docArray = document.getElementsByTagName('font');
var sourceHTML, sourceHref, path, doc, ext, img, docName, fontNode,
linkNode, imageNode;
for(var d=0;d<docArray.length;d++)
{
if(docArray[d].className=='doc')
{
//Get values
fontNode = docArray[d];
sourceHTML = fontNode.innerHTML;
sourceHref=(sourceHTML.substring(sourceHTML.indexOf('"')+1,sourceHTML.indexOf('">')));
path = sourceHref.substring(sourceHref.indexOf('/',8));
doc = path.substring(path.lastIndexOf('/')+1);
ext = doc.substr(doc.length - 3);
docName = fontNode.innerText;
//Determine image
switch(sourceHTML.substr(sourceHTML.indexOf('>')-4,3))
{
case 'doc' : img="msword.png"; break;
case 'xls' : img="msexcel.png"; break;
case 'ppt' : img="mspowerpoint.png"; break;
case 'pdf' : img="pdf.png"; break;
}
linkNode = fontNode.children(0);
linkNode.setAttribute('href','#');
imageNode =
linkNode.insertBefore(document.createElement('img'),linkNode.firstChild);
imageNode.src = 'Skins/Standard/'+img;
imageNode.alt = docName;
linkNode.onclick = function(){loadDoc(sourceHref)};//THIS IS THE
PROBLEM LINE
}
}
}
function loadDoc(filespec)
{
//Dummy code to test the onclick event coding
alert(filespec);
}
window.onload = ModifyLinks;
//-->
</script>
</head>

<body>
<h3>Dynamically Modifying A Tags</h3>

<font class='doc'><a
href="http://localhost:1411/UserData/Test1.doc">Document
1</a></font><br />
<font class='doc'><a
href="http://localhost:1411/UserData/Test1.xls">Spreadsheet
1</a></font><br />
<font class='doc'><a
href="http://localhost:1411/UserData/Test1.ppt">Presentation
1</a></font><br />
<font class='doc'><a
href="http://localhost:1411/UserData/Test2.doc">Document
2</a></font><br />

</body>
</html>

I'd be very grateful for your help - can't figure it out!

Thanks very much.

Regards

Gary

When you're remaking event functions in javascript, the easiest thing
to pass reliably is "this". eg:

<script>
mylink.onclick = function() {window.alert(this.href);}
</script>

which is like:

<a onclick='window.alert(this.href);'
href="http://dilbert.com">asdfds</a>

Also don't use innerHTML, seriously, it will simplify things a great
deal if you don't. For text nodes use nodeValue;

hope this helps
 
G

GaryB

Thanks very much, Guys - used something from each of your comments.

The only thing I'm not sure of, Rob, is how to "...test if 'doc' is one
of the class names, rather than the only class name...".

Thanks very much.

Regards

Gary
 
D

darwinist

GaryB said:
So what is the http://darwinist.googlepages.com/htmldesktop.html link
all about?

Regards

Gary

It's a bunch of free javascript showing how to make and move and resize
and delete and otherwise manipulate document objects.

The source has comments and whitespace, and so is bigger than it might
be for readability, but still only 31k and 751 lines, at present. It
has a simple windowing system that shows how to make movable, trackable
windows in an html environment (images not included).

Pictures and server code would fit easily, but are left out of this
copy to keep the size down and focus on the javascript.

The command box allows you to test stuff immediately and interact with
the virtual desktop and its objects (see the examples), which is
10000x10000 px by default but can be changed. Dragging windows past the
edge of the desktop enlarges it, too.

Web browsers can handle virtually large objects pretty easily, since
they only have to paint the current screen, and html is pretty slim to
keep in memory (don't try to "stretch" a background picture over that
distance though). You can use this knowledge to make fairly large
environments as long as you know which information to get all at once
and you don't bloat yourself too much with overly complex or overly
generalised code.

For example you can simulate the "tabbed" dialog box that windows uses,
by making the tabs links to parts of the document. Some people try to
hide the scrollbars, but what's the point, really. This system uses two
dimensional "tabs" on the navigation box to give you a hundred desktop
areas of a thousand by a thousand pixels each.

You can "goto" or "fetch" open windows and you can rename them while
they are open to keep track of them in the desktop. It's not an
alternative to browser tabs, but an addition to them, since you don't
always want every url to take up all your screen, and keeping track of
titles when you have lots of tabs open can be a pain.

You can steal and customise the code to whatever purpose you desire.
Well, try not to kill anyone, obviously.
 
R

RobG

GaryB said:
Thanks very much, Guys - used something from each of your comments.

The only thing I'm not sure of, Rob, is how to "...test if 'doc' is one
of the class names, rather than the only class name...".

The usual trick is to test it with a regular expression, e.g. to test if
someElement's className attribute contains the class name 'someClass' as
a single word (i.e. delimited by word breaks):

var classTest = new RegExp('\\bsomeClass\\b');

if ( someEl.className && classTest.test(someEl.className))
{
/* The element's className contains someClass as a word */
}
 
G

Georgi Naumov

Hmmm. I'm not very sure but may be in this way will be mutch easily.
more code ...
*********************************************
linkNode.onclick = function(evt){
/*************************************************
In this way the variable linkEmt is
a instance of the link that was
clicked. You can try with different
values for the href attribute. In
Internet explorer the evt is
undefined and we have a additional info
in the event object. Otherwise it
have a target property and several
usefull things.
*************************************************/
var linkEmt= typeof evt == 'undefined' ? window.event.srcElement :
evt.target;

loadDoc(linkEmt.href);
};//THIS IS THE
*****************************************
more code ..
*****************************************
function loadDoc(filespec)
{
//Dummy code to test the onclick event coding
alert(filespec);
}
GaryB напиÑа:
Hi Guys,

I've been battling with this one for hours - I hope that you can help
me!

My code modifies the <a> on a page, from a standard document link into
a link with a tailored onclick event.

It works perfectly (assigning the correct images and the correct
onclick events to the correct <a> tags):
(a) If there's only one link on the page and
(b) If I modify the <a> tags one at a time - hardcoding (if there's
more than one link on the page).

However, if there's more than one link on the page, my code assigns
each onclick event to all of the previous nodes in the array instead of
each one independently. (I've commented the problematic line of
javascript, with "THIS IS THE PROBLEM LINE"). I must be missing
something!

Here's a page with the code (including a dummy loadDoc function). It
should show the problem as is (the images obviously won't show):

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Modify A Links</title>
<link href="ProdsolEpd.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="ProdsolEpd.js"></script>
<script language="JavaScript" type="text/javascript">
function ModifyLinks()
{
//Create Document links
var docArray = document.getElementsByTagName('font');
var sourceHTML, sourceHref, path, doc, ext, img, docName, fontNode,
linkNode, imageNode;
for(var d=0;d<docArray.length;d++)
{
if(docArray[d].className=='doc')
{
//Get values
fontNode = docArray[d];
sourceHTML = fontNode.innerHTML;
sourceHref=(sourceHTML.substring(sourceHTML.indexOf('"')+1,sourceHTML.indexOf('">')));
path = sourceHref.substring(sourceHref.indexOf('/',8));
doc = path.substring(path.lastIndexOf('/')+1);
ext = doc.substr(doc.length - 3);
docName = fontNode.innerText;
//Determine image
switch(sourceHTML.substr(sourceHTML.indexOf('>')-4,3))
{
case 'doc' : img="msword.png"; break;
case 'xls' : img="msexcel.png"; break;
case 'ppt' : img="mspowerpoint.png"; break;
case 'pdf' : img="pdf.png"; break;
}
linkNode = fontNode.children(0);
linkNode.setAttribute('href','#');
imageNode =
linkNode.insertBefore(document.createElement('img'),linkNode.firstChild);
imageNode.src = 'Skins/Standard/'+img;
imageNode.alt = docName;
linkNode.onclick = function(){loadDoc(sourceHref)};//THIS IS THE
PROBLEM LINE
}
}
}
function loadDoc(filespec)
{
//Dummy code to test the onclick event coding
alert(filespec);
}
window.onload = ModifyLinks;
//-->
</script>
</head>

<body>
<h3>Dynamically Modifying A Tags</h3>

<font class='doc'><a
href="http://localhost:1411/UserData/Test1.doc">Document
1</a></font><br />
<font class='doc'><a
href="http://localhost:1411/UserData/Test1.xls">Spreadsheet
1</a></font><br />
<font class='doc'><a
href="http://localhost:1411/UserData/Test1.ppt">Presentation
1</a></font><br />
<font class='doc'><a
href="http://localhost:1411/UserData/Test2.doc">Document
2</a></font><br />

</body>
</html>

I'd be very grateful for your help - can't figure it out!

Thanks very much.

Regards

Gary

gb at prodsol dot co dot nz
 
R

RobG

Georgi said:
Hmmm. I'm not very sure but may be in this way will be mutch easily.

Please don't top-post here. Reply below a trimmed quote of what you
are replying to.

more code ...
*********************************************
linkNode.onclick = function(evt){ [...]
var linkEmt= typeof evt == 'undefined' ? window.event.srcElement :
evt.target;

loadDoc(linkEmt.href);
};//THIS IS THE

That is unnecessary and assumes that the funciton call has not bubbled
up from some element lower in the DOM tree. A function reference can
be attached simply using:

linkNode.onclick = loadDoc;


Then a reference to the element that called the function will be held
in the function object's 'this' object when executed:

function loadDoc(){
alert(this.href);
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,983
Messages
2,570,187
Members
46,747
Latest member
jojoBizaroo

Latest Threads

Top