tags:

views:

48

answers:

2

I have a page containing a series of tags like this

 <a class="IMG" href="#" onclick="openWin(this,'./photos/Snapshot_20100803.jpg');return false;"><img src="./photos/TN_Snapshot_20100803.jpg" alt="./photos/TN_Snapshot_20100803.jpg"/></a> 

openWin creates a window and displays the image when the thumb is clicked. That page also contains a 'next' button which calls a nextImage function in the parent page's script. nextImage hunts through the a class IMG tags and finds the following a tag with class IMG. But now I'm stuck. I've found the right a tag and have it in var z. I can get something ala

cmd = z.onclick;

if I display cmd with alert(cmd) I see something like this

function onclick(event) { openWin(this, "./photos/Snapshot_20100804.jpg"); return false; }

but I don't know what I have. I don't seem to be able to manipulate it as if it's a string using indexOf.

What kind of thing have I glommed onto?

How can I manipulate it as a string?

Is there some way I can define the function perhaps using eval() and execute it in the context of the tag in the page containing the a tag?

What I really want to do is click the a tag I found in the page.

A: 

If you have something like this:

var z = 'function onclick(event) { openWin(this,"./photos/Snapshot_20100804.jpg"); return false; }'

You can easily do this to execute the string contained in z:

var cmd = "("+z+")();"
eval(cmd);

You can test it HERE.

Cipi
He *can*, yes. It's just a really, really bad idea. :-)
T.J. Crowder
Why? Because he cant be sure whats contained in z?
Cipi
@Cipi: There are lots of reasons to avoid `eval`, but in this case one good reason is the one you picked up on in my answer: Function decompilation is non-standard.
T.J. Crowder
+1 for teaching me something new. ;)
Cipi
+2  A: 

What you've found in z is the HTMLElement instance for the a element. When you look at its onclick property (which is a reflection of its onclick attribute), you get a Function instance. The toString of a Function instance, on nearly all implementations, returns a string containing a decompiled version of the function. However, this is non-standard behavior and is expressly disallowed in the latest JavaScript specification's new "strict" mode. In any case, decompiling the handler is not how you want to solve this problem. :-)

If you can modify the HTML, I'd recommend encoding the target picture as a data attribute, like this:

<a class="IMG" href="#" data-img='./photos/Snapshot_20100803.jpg' onclick="openWin(this,this.getAttribute('data-img'));return false;"><img src="./photos/TN_Snapshot_20100803.jpg" alt="./photos/TN_Snapshot_20100803.jpg"/></a>

Then, when dealing with the "next" feature, you can simply find the next a element (I'll call it nextLink) and do this:

openWin(nextLink, nextLink.getAttribute('data-img'));

Better yet, have the openWin function read the data-img attribute itself so that the HTML can just be:

<a class="IMG" href="#" data-img='./photos/Snapshot_20100803.jpg' onclick="openWin(this);return false;"><img src="./photos/TN_Snapshot_20100803.jpg" alt="./photos/TN_Snapshot_20100803.jpg"/></a>

...and the call to open the next one on nextLink just:

openWin(nextLink);

Shortens the page a bit, not having to repeat all of those this.getAttribute('data-img') bits.

Custom attributes with the prefix data- are valid as of HTML5, and they work with all browsers even with earlier doctypes now (it's just that technically they aren't valid in earlier doctypes; I'm not aware of any browser that cares).

Going a bit off-topic, if you're allowed to make bigger changes, you can ditch the onclick on the a tags entirely and instead use event bubbling by hooking the click event of whatever container holds all of these a elements. This is because unless cancelled, a click travels up the tree (from child to parent) until it is handled, and you can figure out by looking at the event object which child was actually clicked (so you can get its data-img attribute.) If you can/want to introduce a library like jQuery, Prototype, Closure, etc., they can simplify doing that markedly.

T.J. Crowder
Oh I see now why eval() is bad... =D
Cipi
Thanks a bunch. More to ponder. I had actually though along the lines of the data-img tags but a search of W3 didn't turn up anything I could use. Is the data business supported in firefox 3.0.19 and IE 8. I've avoided the event business because I'm a beginner and have no experience with that topic; maybe it's time to delve in.
Mike D
@Mike D: I've never found a browser where non-standard attributes were an issue, certainly all the mainstream ones are fine with it. AFAIK, it's just a validation issue; how much of an issue it is for you depends on whether validation is an important part of your development cycle (validating is a Good Thing(tm)). (If it is, you could consider making the jump to the HTML5 doctype now; it [works just fine](http://ejohn.org/blog/html5-doctype/) (that's a link) even in browsers that don't explicitly support HTML5 stuff yet.)
T.J. Crowder
I've changed things around so the a tag contains onclick="openWin(this) and the img link is passed as data-img=. Are you suggesting that in openWin(nextLink) be the JavaScript for the next button and that openWin put the proper thing there as obtained from getElementByTagName? openWin will still have to do a getElementByName to find nextLink unless context is preserved some how.
Mike D
@Mike D: Sounds like you're headed the right way. Now that you've done that, I'd have `openWin` use `getAttribute` to get the value of the `data-img` (if you haven't already). The "next" functionality can use `getElementsByTagName`, but you might also want to look at `nextSibling`, `parentNode`, and `childNodes`/`firstChild` in the DOM spec: http://www.w3.org/TR/DOM-Level-2-Core/core.html Have fun! (Just be aware that there are many different kinds of nodes; the kind you're interested in -- Elements -- are `nodeType == 1`.)
T.J. Crowder
I've pretty much done as you suggest including replacing the onclick call with a openWin call in the next function. What about using some global vars set by openWin to hold the next a tag? I suppose globals are frowned on. Thanks for the help. I'm more-or-less playing building this site for my wife's genealogy and learning a bit about JS. Can you recommend any JS book? One thing I'd really like to see is the name space laid out.
Mike D
@Mike D: Yes, globals are frowned upon; here: >:-| There's no need for them in this case, when you kick off the `openWin` function originally, set up a click handler on the result that uses the passed-in element as a starting point for finding the next one. Re JavaScript books, I think *JavaScript: The Definitive Guide* by David Flanagan (currently 5th ed; http://oreilly.com/catalog/9780596101992) is pretty good, but it's been years since I looked at them so it could have been surpassed. I keep meaning to do a blog series called "JavaScript: A gentle introduction" but haven't got to it yet.
T.J. Crowder
@crowder: what I'm doing now is having the onclick button for the next button call a nxtimg function with the index (of the getElementsByTagName) item being displayed. I tried to figure out a way to put a actual reference to a a tag there but couldn't accomplish that. The local library has the Flanagan book and I've ordered it to examine.
Mike D