Today I finished some changes to this blog-software – most important is the possibility to get an email whenever someone comments an article you are watching.
There is nothing too fancy going on, but I had some problems with the Internet Explorer and dynamically assigned event handlers.
Since the form to submit a comment is fetched via XML and Javascript (AJAX), I have to create all the elements of the form using various DOM methods. Most stuff can simply be assigned using the following method:
var obj = document.createElement('div');
obj.setAttribute("id", "my_id");
There is one well-known caveat to this if you want your code to be compatible with the Internet Explorer; if you want to assign a CSS-class, you must do that using 'className' instead of 'class' only:
obj.setAttribute("className", "my_class");. Simply do a browsercheck and then use 'className' or 'class' accordingly.
However, I stumbled upon a more difficult problem:
Assinging event handlers (like
onsubmit,
onmousedown or
onfocus) to DOM created objects. To check if a browser supports my AJAX-methods, I use code which executes JavaScript on specific events like
<form onsubmit="if(formSubmitted(this)){return false;}">. The Gecko-Engine and Safari let you assign that event-handler like mentioned above, simply using
obj.setAttribute(), but this won't work in Internet Explorer 6; I haven't testet IE7 yet.
What I have done is putting the 'string' which contains our code inside an
eval() statement and built this eval() statement into an
anonymous function. Maybe there is a simpler solution, here is a code block which (in
fat) demonstrates how I did it.
// event handlers
var is_IE = (navigator.appName.indexOf("Explorer") > -1);
var poss = new Array('id', 'type', 'name', 'value', 'class', 'style', 'href', 'method', 'action', 'for', 'src', 'title', 'alt', 'size', 'checked', 'disabled');
var handler_poss = new Array('onsubmit', 'onclick', 'onfocus', 'onblur', 'onmousedown', 'onmouseup');
var xhtml = document.createElement(xml_tree.nodeName);
var attr_value = new Array();
for(var i = 0; i < xml_tree.attributes.length; i++) {
var attr = xml_tree.attributes[ i].name;
// 'normal' attributes
if(in_array(attr, poss) >= 0) {
xhtml.setAttribute(((is_IE && ('class' == attr)) ? 'className' : attr), xml_tree.getAttribute(attr));
}
// event handlers
else if(in_array(attr, handler_poss) >= 0) {
if(is_IE) {
attr_value[attr] = xml_tree.getAttribute(attr) ? xml_tree.getAttribute(attr).replace(/return /ig, "ret_val = ") : null;
try {
if('onsubmit' == attr)
xhtml.onsubmit = function() { var ret_val = true; eval(attr_value['onsubmit']); return ret_val; };
else if('onclick' == attr)
xhtml.onclick = function() { var ret_val = true; eval(attr_value['onclick']); return ret_val; };
else if('onfocus' == attr)
xhtml.onfocus = function() { var ret_val = true; eval(attr_value['onfocus']); return ret_val; };
else if('onblur' == attr)
xhtml.onblur = function() { var ret_val = true; eval(attr_value['onblur']); return ret_val; };
else if('onmousedown' == attr)
xhtml.onmousedown = function() { var ret_val = true; eval(attr_value['onmousedown']); return ret_val; };
else if('onmouseup' == attr)
xhtml.onmouseup = function() { var ret_val = true; eval(attr_value['onmouseup']); return ret_val; };
}
catch(exc) { }
}
else {
xhtml.setAttribute(attr, xml_tree.getAttribute(attr));
}
}
}
Notes:
- You cannot use a return from inside an eval() statement. That's why I replace all occurrences of 'return' and assign the values to a variable ('ret_val' in this case) and return after the eval statement.
- I had to use the hard-written names of the events ('onsubmit', 'onclick' and so on) although the variable 'attr' carries the same information. Using 'attr' instead results in much simpler code, but you can not use more than one event handler per element or always the last handler will be executed for every preceding handler.
Rafael: Thank you very much, I was having a huge headache to solve the very same problem!