Monday, November 17, 2008

Using a Javascript Framework

There are many Javascript frameworks popping up all over the internet. At this point, I need to pick one for a project I'm working on and the decision is not easy. I have to look at all the possibilities such as performance, size of library, adoption, documentation, and of course features and complex features such as an effects library.

Thankfully there are a lot of resources on the net to help and that is what this article will point you too. Some of the common resources I used to arrive at my decision. First off, this web site http://www.javascriptlibraries.com/ gives a great summary of the different javascript libraries, effects, and tools available today. As of this writing, it seems to be fairly up to date. So that's where I'd look if you're in the market for a library.

As far as performance goes, there is a great web site (slickspeed)that tests the selector performance of some of the top javascript libraries. It includes MooTools, JQuery, Prototype, YUI, and Dojo. This will be give you an idea of how the libraries may perform differently. In general, selector performance may or may not be important to you.

After spending a lot of time analyzing the different frameworks (Analysis Paralysis), I decided to use JQuery for the simple fact that it had great feedback and was easy to find great documentation and I was able to start using it right away. For a cross-browser library, it is incredible. It has so far solved nearly all the problems I've discussed in my blog. However, I will still continue to write about the different cross-browser issues I find as I replace the code with JQuery code.

Tuesday, September 30, 2008

Difference between parentNode and parentElement

Just a quick blog post to vent the frustration as I continue to convert a very large web application to a fully cross-browser compatible site. Over 150 lines of code refer to parentNode. parentNode is compatible with IE4+ and Safari 1.2+ of all things. To make this fully standards compliant, you can pretty much blindly replace parentNode with parentElement. Although they are very very simliar, they do have some differences. If we're talking about a standard element then they work the same. However, if you have an attribute or text node or something else then there will be some differences. That's it for now. Hope this helps!

Monday, August 18, 2008

Generic Events - Part 1

In my previous article, I discussed the different ways to bind to events in a browser agnostic fashion. In this article, I discuss how to create a generic function allowing you to bind to events in almost any browser.

In general you use either the Internet Explorer specific attachEvent or the W3C addEventListener functions when programmatically binding to events.

These functions are similar in behavior and we can make use of that to create a generic function that use either of these. One of the most frustrating things I've found with the W3C event support is the fact that it doesn't support the window.event object. Instead, it implicitly passes the event object to the function. I had to get that out and I will discuss it in future blogs, however, it has nothing to do with this article:-)

Here is the proper use of attachEvent in an IE browser:

document.getElementById("test").attachEvent("onclick", function(){alert('onclick was called');});

And here is the proper use of addEventListener in W3C browsers:

document.getElementById("test").addEventListener("click", function(evt){alert('click was called'), false);

Note that you either use the name of a function or an anonymous function. As well addEventListener has an extra parameter for capturing events. At this point we will ignore that extra parameter by passing in false.

Okay, so now that we know how to use them in the simplest case, here is a function that allows us to add events in a generic manner:

function addEvent(elem, eventName, func)
{
if (elem.attachEvent)
{
elem.attachEvent('on' + eventName, func);
} else if(elem.addEventListener)
{
elem.addEventListener(eventName, func, false);
}
}


Note that addEventListener doesn't prefix events with the on keyword so when calling the addEvent function just pass in the event name and we append the on prefix as necessary.

That's it for now. This function went a long way when converting my client's web site to support W3C browsers. In fact you won't believe how easy it is to use and begin replacing once you get started.

Sunday, July 27, 2008

Cross-browser Javascript Events

So you're trying to convert your website from an IE specific site into a cross-browser compatible web site. You've probably noticed that the event object is not available in the current event as is the norm for Internet Explorer. In fact when supporting events in a cross-browser manner you must plan ahead.

There are three ways that you typcially hook up events in a browser. For example to hook up the onclick event you could add the onclick attribute to the tag you want to bind to:

<div id="test" onclick="doit();">Some Content</div>

Another way is to select the tag in javascript and use the onclick attribute as follows:

document.getElementById("test").onclick = doit;

and finally, the last method is to use the bind method which is called attachEvent in Internet Explorer and a similar event is called addEventListener in W3C browsers:

document.getElementById("test").attachEvent("onclick", doit);

The project I'm working on typically uses the first and last of these methods. In Internet Explorer, you can expect that the window.event object contains the current event. In W3C compatible browsers, for the first method above, you have access to a special event keyword that you can pass to your function. In the last two methods, the event is implicitly passed in.

Here's an example of using the event keyword for the first method:

<div id="test" onclick="doit(event, "myarg");">Some Content</div>

For the second method, here's an example of how to pass multiple parameters assuming that the event object is passed implicitly to the specified function:

document.getElementById("test").onclick = function(evt){doit(evt, "myarg");};


Finally, in the last example, here is how you'd pass the event object to W3C browsers:

document.getElementById("test").addEventListener("click", function(evt){doit(evt, "myarg");}, false);

That's it so far. In my next blog I show you how to take this information and create some rudimentary functions that will allow you to easily support events in a cross-browser manner.

Wednesday, July 23, 2008

Browser Compatible Mouse Events

As I continue on the path of converting an IE specific web site into a browser-agnostic web site I found that not all mouse events are the same. What I mean is, Internet Explorer 5.5 introduced the onmouseenter and onmouseleave event handlers. This is after everybody and their brother already support the onmouseover and onmouseout terminology which do exactly the same thing. By the way, don't get me wrong, I actually think the IE naming convention makes more sense. This is pretty much one of the most uninteresting and easily fixable browser issues I've come upon so far. The problem was finding the issue. When you think you know something that is so obvious like:

<div onmouseenter="dosomething();">Some text</div>

You continue to bang your head against the wall when it works in Internet Explorer but fails in Firefox.

So when you're fixing up your web site to make it fully cross-browser compatible. Make sure to use the classic onmouseover and onmouseout events.

Tuesday, July 22, 2008

How About a Quick Debug Output Window

One of the first things most Javascript developers learn is how to display an alert box. As they progress in their Javascript skills, they very soon realize that it's a bit of a black box and start to use those alerts to debug their code. Javascript has progressed over time and nowadays there are pretty decent debuggers. But often times you just need a console window to write output to. I wanted to write a very small little piece of code that allowed me to write debug output. This piece of code would allow me to simply paste it into the current Javascript I'm debugging and with one command, allow me to write to the debug window. I wanted to use Object Literal Syntax (AKA JSON) as well so I don't have to instantiate an instance of it. Well, with just a few lines of code, I was able to do that and I wanted to share it with you. It's not rocket science and would be fun to modify to see how much bang for your buck you could get out of it. Let me know what you think and even throw some suggestions out or add some code. Just paste this code somewhere into the Javascript code your are using:


var DBG = {
write : function(txt){
if (!window.dbgwnd){
window.dbgwnd = window.open("","debug","status=0,toolbar=0,location=0,menubar=0,directories=0,resizable=0,scrollbars=1,width=600,height=250");
window.dbgwnd.document.write('<html><head></head><body style="background-color:black"><div id="main" style="color:green;font-size:12px;font-family:Courier New;"></div></body></html>');
}
var x = window.dbgwnd.document.getElementById("main");
this.line=(this.line==null)?1:this.line+=1;
txt=this.line+': '+txt;
if (x.innerHTML == ""){
x.innerHTML = txt;
}
else {
x.innerHTML = txt + "<br/>" + x.innerHTML;
}
}

To write to the console, just add this line:

DBG.write("This is console output!!");

Enjoy!!

Monday, July 21, 2008

The cloneNode Problem

This is the first entry into the foray of problems that I found when trying to create cross-browser compatible javascript. As I mentioned before, a client of mine is converting their web site from Internet Explorer(IE) to a fully cross-browser compatible web site. That includes IE6 (uggg), IE7, Firefox 3.0, and Safari 3.1.

So anyway, the cloneNode problem. Here's the issue. I needed to replace the IE specific outerHTML function (which I'll discuss in another blog) with a cross-browser version. It turned out that the cloneNode function would make it very easy to do that. The problem was, in very specific cases (i.e. my case), it didn't exactly clone everything. You see, there's a bug (suprise), that appears to be in IE, in which when you make dynamic modifications to the HTML before calling cloneNode, it doesn't clone the node exactly. It just sort of copies most of it..... Blah. Well, here's some example code for you to try for yourself:

<html>
<head>
<title>Javascript Today - cloneNode bug</title>
<script>
function runit()
{
var node = document.getElementById("checkbox");
node.checked = true;
var wrapper = document.getElementById("wrapper");
alert(wrapper.innerHTML);
var cloned = wrapper.cloneNode(true);
alert(cloned.innerHTML);
}
</script>
</head>
<body id="bod">
<div id="wrapper">
<input id="checkbox" type="checkbox">
<a href="javascript:runit();">Click Me to See Bug</a>
</div>
</body>
</html>

Note that the code that is displayed in the alert is different each time. Perhaps there is an easy workaround. In a lot of cases the cloneNode function works soundly but don't depend on it. If you are only planning on using the innerHTML property then you may want to just take the innerHTML and assign it to the innerHTML of another element. In a future blog, I will show you how I duplicated the IE specific outerHTML function in a cross-browser manner. Hope this helps and talk to you later.