Forum Moderators: open
Instead of looping through the elements, i was manually setting a variable to a new link class (commented out in createLinks). Then I was manually setting onmouseover="link1.highlight()", which was working, but now I'm trying to late-bind it. So hopefully I can further adjust this code to make it fully automated in future.
Any help is appreciated to get attachEventListener to work. Note: at the moment pageLoad() only calls createLinks() and getObjById() can be replaced with getElementById()
JavaScript
/* MENU FUNCTIONS
---------------- */
var lnk = new Array();
var obj = new Array();
function createLinks() {
//link1 = new linkClass('btn_home',null,0,-288,-72, 72, 33); link1.formatLink();
var d = document.getElementsByTagName('div');
for(i=0; i < d.length; i++) {
var e = d[i].getElementsByTagName('a');
if (d[i].className.match(/.+change/g)) {
for(j=0; j < e.length; j++) {
lnk[lnk.length] = e[j]; // adds a node to the array
last = lnk.length-1;
l = lnk[last];
l.id = "button_" + (last<10?"0"+last:last);
obj[last] = new linkClass(l.id,null,0,-288,-72,72,33); obj[last].formatLink();
//d[i].addEventListener("onmouseover",function(){eval("obj["+last+"].highlight()")} , false);
//e[j].addEventListener("onmouseout", function(){eval("obj["+last+"].changeImage()")}, false);
obj[last].highlight();
obj[last].changeImage();
}
}
}
}
function linkClass(objId, obj, startPos, maxPos, step, width, height) {
this.imgWidth = width;
this.imgHeight = height;
this.obj = obj!=null?obj:getObjById(objId);
this.objId = objId;
this.posCurr = startPos;
this.posMax = maxPos;
this.posStart = startPos;
this.posStep = step;
this.tmpDelay = 0;
this.timeoutId = 0;
}
linkClass.prototype.delay = 125;
linkClass.prototype.changeImage = changeImage;
linkClass.prototype.formatLink = formatLink;
linkClass.prototype.highlight = highlight;
function formatLink () {
with (this.obj.style) {
var w = this.imgWidth;
var h = this.imgHeight;
width = w < 0 ? w * -1 : w + "px";
height = h < 0 ? h * -1 : h + "px";
}
}
function highlight(href) {
with (this) {
window.clearTimeout(timeoutId); // clear last timeout
posCurr = posStart;
obj.style.background = "transparent url(Menu_Home.png) no-repeat " + posCurr + "px 0px;";
obj.href = href;
}
}
function changeImage(paramDelay) {
with (this) {
tmpDelay = (typeof paramDelay == 'undefined')?delay:paramDelay;
if (posCurr > posMax) {
obj.style.background = "transparent url(Menu_Home.png) no-repeat " + posCurr + "px 0px;";
posCurr += posStep;
timeoutId = window.setTimeout(function (){changeImage(tmpDelay);},tmpDelay); // passing a function solves errors
}
}
}
<body onload="javascript:pageLoad();">
<div id="body">
<div id="header">
<div class="menu">
<div class="img"> </div>
<div class="img btn change" ><a href="#"></a></div>
<div class="img btn change" ><a href="#"></a></div>
<div class="img"> </div>
</div>
</div>
</div>
</body>
body {
background: #EEEEFF;
font-family: verdana, arial, "lucida console", sans-serif;
font-size: 12px;
margin-left: auto;
margin-right: auto;
margin-top: 0;
text-align: center;
width: 800px;
}
div#body {
border: 1px solid #336666;
background: url(bg.png) repeat top left;
width: 800px;
}
div#header {
background-image: url(Work_01.png);
height: 175px;
position: relative;
text-align: left;
width: 800px;
}
div#header .menu {
bottom: 0px;
display: inline;
float: left;
margin-bottom: 25px;
position: absolute;
text-align:center;
}
/* BTN DEV TESTING FOR MENU */
div.btn a {
display: inline;
float: left;
height: 33px;
background: transparent url(Menu_Home.png) no-repeat -216px 0px;
}
div.divider {
background-color: #666699;
height: 1px;
margin: 3px auto 5px 0px;
padding: 0px 0px 0px 0px;
width: 100%;
}
div.img {
display:inline;
float:left;
}
div.img img {
border: 0px solid black;
}
[edited by: vol7ron at 10:15 pm (utc) on Mar. 7, 2008]
The additional problem is the value of [i]last, which will not have the expected value at the time of executing the onmouseover event handler, it will always be set to the last one, regardless of the source of the event handler. Using this in this context will resolve to the source of the event handler, so either the <div>, either the <a>.
If you would like to keep track of the the linkClass instance similar way as you have done, then move the even handler definitions into a new function:
function attachEventHandlers(oDiv, oLink, linkObj) {
oDiv.addEventListener("mouseover",function(){linkObj.highlight();} , false);
oLink.addEventListener("mouseout", function(){linkObj.changeImage();}, false);
} Now the value of the linkObj variable will be remembered, and when the event handler is triggered, it will use these 'saved' values, so your script will behave as expected.
And of course change the loop accordingly:
// ...
for(j=0; j < e.length; j++) {
lnk[lnk.length] = e[j];
last = lnk.length-1;
l = lnk[last];
l.id = "button_" + (last<10?"0"+last:last);
obj[last] = new linkClass(l.id,null,0,-288,-72,72,33);
obj[last].formatLink();
//
attachEventHandlers(obj[last]);
//
obj[last].highlight();
obj[last].changeImage();
}
// ... You can play around with this on FireFox for example, but to make it run on more browsers, you need to change the attachEventHandlers function, for example to make it Internet Explorer compatible, or make it possible to work on old, DOM Level-1 browsers as well.
Check out the names, Dean Edwards and Zidjel. There was a contest, recently, for an alternative which could adequately control and remove handlers, in IE.
I found it didn't work so well for 'onscroll', being a global sort of thing to begin with. So I wrote a separate and lone module to handle IE scrolling. All elements get added to that, rather than having events added to assorted elements. All the elements are handled by the one module run by onscroll. But stacking the events to specific elements should work fine, otherwise, as Zidjel (is that right?) proposed, and Edwards too, and through their assorted variations on the same.
But it's a 'can of worms'. You just never know. The simple things can prove to be very time consuming. Who would have thought, attachEvent?
gergoe, as for the function itself, I am not too keen on variable names or the order. I am just in development and during development/testing, I'm trying lots of different ways. Right now, I have not optimized the logic; there may also be vestigial variables. I'm more concerned with getting it to work and then cleaning up later :)
thx for all your help guys
Try moving it to the function as suggested and see if it works as expected, and after that, you can do some research on Javascript Closures, because that's what you and me were doing with those functions.
If you have no clue what I'm talking about then you don't know if it was either a problem or if it was germane to your problem. C'mon. Take time to read what you write.
Whether you wish to obfuscate or 'minify', I was saying, and I'll repeat myself, that when you get to IE6, for example, you will be faced with a choice of trying to accomodate the M$ attachEvent design, or adopting an alternative. You can search the names I suggested. They developed - an alternative - to attachEvent, in order to fix the various problems with IE's design.
Any better?
This is actually a problem area, particularly when it comes to IEStatement that it's a common problem, thank you.
Check out the names, Dean Edwards and Zidjel. There was a contest, recently, for an alternative which could adequately control and remove handlers, in IE.Statement that someone else had a solution for IE, thank you.
I found it didn't work so well for 'onscroll', being a global sort of thing to begin with...Statement that you found a solution through using onscroll, thank you.
Your post still is still fluffy. It just said, "hey you'll have problems with IE, go search for an answer, you can start here." I do appreciate your attempt though, and thank you for taking the time to respond to my problem, so don't misunderstand me, but I feel like you didn't read my original post because you didn't really show me an example or provide a solution.
I guess I was looking for problems/suggestions in the code I wrote above. If you look at gergoe's post that's more of what I was looking for, which I will try when I get back to work tomorrow.
This is something that I should know, I've just been away for too long and am mad that I'm getting old and forgetful. A few months ago I also de-obfuscated Google suggest and added comments. I have several AJAX e-books, but only some have a like-google approach, whereas the code I had was Google's, but clarified. It would have been a prime example because it uses on/over events. Anyhow, I've lost most of the code, but have begun redoing it :( I didn't do it to copy them, only to learn their approach.
Thank you all so much for your help, I really appreciate it and will try to help you where I can. I also do appreciate your IE interjections, fside, because there is no doubt that I will have to make it IE compatible. My concern right now was just for FF because the site is not public, it's for an intranet that primarily uses FF - go figure? However, I do hope to use this knowledge for some of my personal sites in the future.
Thx again,
vol7ron
Removing "on" from the event names, helped out a bit and I understand what you're saying about the objects - without the function this only works for the last rollover, but that's why I tried to tie them to global arrays. With the function, one of the images don't show up and the rollover doesn't work.
I've tried modifying the function from:
function attachEventHandlers(oDiv, oLink, linkObj) {
oDiv.addEventListener("mouseover",function(){linkObj.highlight();} , false);
oLink.addEventListener("mouseout", function(){linkObj.changeImage();}, false);
}
And of course change the loop accordingly:
// ...
for(j=0; j < e.length; j++) {
lnk[lnk.length] = e[j];
last = lnk.length-1;
l = lnk[last];
l.id = "button_" + (last<10?"0"+last:last);
obj[last] = new linkClass(l.id,null,0,-288,-72,72,33);
obj[last].formatLink();
//
attachEventHandlers(obj[last]);
//
obj[last].highlight();
obj[last].changeImage();
}
// ...
// call the function
attachEventHandlers(d[i ],e[j],obj[last]);
// function definition
function attachEventHandlers(oDiv, oLink, linkObj) {
oDiv.addEventListener("mouseover",function(){linkObj.highlight();} , false);
oDiv.addEventListener("mouseout", function(){linkObj.changeImage();}, false);
}
Which I messed up at first, but does work! Thank you very much. I do see some delay, which I'm hoping I can fix. But this is awesome and now all of fsides suggestions I'm sure will come into play :)
I still don't fully understand how the separate function changes the scope of the object, or really what is going on there, but I will study it and make modifications as I see fit.
I hope this post will help someone with their multi-state rollovers in the future.
vol7ron
function attachEventHandlers(oDiv,oLink, linkObj) {
try {
oDiv.addEventListener("mouseover", function(){linkObj.highlight();} , false);
oLink.addEventListener("mouseout", function(){linkObj.changeImage();}, false);
} catch (err) {
oDiv.attachEvent("onmouseover", function(){linkObj.highlight();});
oLink.attachEvent("onmouseout", function(){linkObj.changeImage();});
}
}
fside, I haven't come across any problems with this, I might want to put a browser-sniffer function in there, but the attachEvent works fine for now. Your previous statements made more sense as I approached this. thx
vol7ron
That's not the issue. You don't even need try/catch. Just test for the method directly. Scott Andrew (LePera) [jszen.blogspot.com] simple cross-browser function [scottandrew.com]. However:
When you get to the attachEvent branch, "the hidden assumption behind addEvent() is that addEventListener and attachEvent work exactly the same. They don't." . . . "If you don't really understand the difference between addEventListener and attachEvent, stick to the traditional event registration model:", namely one handler per object event, e.g. $("divA").onclick = clickHandler.
QM Problem Identification [quirksmode.org]
I won't rephrase all the considerations, here. I would suggest you look instead at this [therealcrisp.xs4all.nl]. And based on that, here is [dean.edwards.name] Edwards updated alternative to attachEvent, etc.
This is what I was getting at. I just thought you might 'google' it on your own.
For my code in FF2/IE6 they both operate seemingly the same, however I do still need to research the memory leaks and what is going on. My first pass I just wanted to make sure everything was possible and have the ability to show a test site, my next pass I'll do some more heavy duty research and make things more efficient.
I appreciate your persistence, fside. Thank you.
- vol7
Removing "on" from the event names, helped out a bit and I understand what you're saying about the objects - without the function this only works for the last rollover, but that's why I tried to tie them to global arrays. With the function, one of the images don't show up and the rollover doesn't work.
I still don't fully understand how the separate function changes the scope of the object, or really what is going on there, but I will study it and make modifications as I see fit.
Anyway, my explaining skills are rather limited, so I'd suggest you to do some research on JavaScript Closures (as I mentioned earlier), and find a better presenter than me ;-)
No problem. The idea wasn't that the method was faster, just that try/catch wasn't needed. I just got a CCed email from this Filipack guy telling everyone I was trying to 'fool' people by noting the work of Edwards, Zijdel, etc, above. He said no 'experienced programmer' would fall for it, or something. Well, I consider Dean Edwards to be an experienced programmer. And I think it's better to take advice from them. I can't emphasize that, enough. You get too many self-proclaimed 'experts', operating on their own 'authority'. I prefer to point in the direction of those who are on record as having gotten things right, those who know what they're talking about.
I have now finished my rollover, which is working beautifully. Now, I'm modifying it to use (5) 1x33 pixel bg images for the animation effect, and a text overlay. I'm also making the code a little more robust so that a user can have the rollover images side-by-side or one-below-the-other.
The major change I included in my HTML/JavaScript was to perform the attachments on load for IE and on DOM finished loading for Firefox. Everything is working flawlessly now. Though, I haven't looked at the one scope issue noted above. I have, however, looked at the differnce with attachEvent and noted the biggest difference being how "this" is interpreted by the window rather than the calling object.
My next step is to include some unloading to free up memory. Though, I believe I saw some memory-leak issues with passing pointers through functions. Argh, so much to do.
Thx again guys.