No Mod Required

Archive for the 'javascript' Category

I'm not sure I'd jump to pay money for TypePad after witnessing this:

I was browsing the TypePad Blog and Blogging Comparison Chart (not that I'm thinking of switching, it was just for work,) when one of my co-workers pointed out the rapidly growing firebug error count in the lower right corner. By the time I looked it had grown to well over 4000 errors. It seems like someone over there doesn't quite know how to use jquery? I'm sure it's something simple, but that doesn't mean it won't potentially hurt their chances to sell their pay blogging platform*.

4295-errors.jpg

Click for the full screen shot.

someones-made-a-boo-boo

*Although I wonder how much it would actually effect them? What are the demographics of someone who would go for a pay blogging platform? Would they be technical enough to notice JavaScript errors (especially in that abundance) and recognize them as a potential problem? Or would anyone looking for a pay solution be going to it because it presumably offers some level of real technical support? Anyone know?

I also wonder how long it's been broken.

Answering Google- Passing a Random Number to a Div id in Javascript

Occasionally I see specific searches that bring people to my site and I wonder if people actually found the answers they were looking for in my code articles. Sometimes I think they probably did, but sometimes I'm not so sure. So… I figured why not answer some of the more interesting pleas directly? Lord knows if anyone will ever need to do such a thing again, but if they do I'll be ready for them (and I get to problem solve in public :) )

Anyway, here's one that I thought was interesting. The exact search was:

how to pass random no to div id in javascript

The first result points to this site, but I'm almost certain the article it points to won't be of any help.

This function would be of great help

function random_div_id(obj) {
//obj is the div to be randomized
//get a random integer between 1 and 10000
     rand_id = parseInt(Math.random()*10000);
//concatenate the old id, a dash and the random number into a new random id
//if you wanted, you could just pass the rand_id and be done with it.
     obj.setAttribute("id",obj.id+"-"+rand_id);
}
 

Here's an example:

A static variation on JavaScript's getElementsByTagName

As I mentioned yesterday I wanted to offer up an alternative to the browser crushing example I made to illustrate the point about Javascript Objects. So here it is…

Instead of using getElementsByTagName("a") and watching the count grow towards infinity, I simply added a new function which does the same thing as getElementsByTagName, except that it takes a "snapshot" of the nodeList and turns it into a plain old Array. So, unlike a variable created with getElementsByTagName, this one will not track changes to the underlying DOM collection.* I've illustrated this with a count of the members of the two collections before and after the manipulations are run.

Here's a sample:

And here's the function

function getStaticCollectionByTagName(tag, node) {
  //just like getElementsByTagName, we want to open up and optional context node 
  if (node==undefined) {
  //if it's not passed in as an argument, we set it to be document 
  node=document
  }
  //we build a variable with the original collection 
  var temp_array = node.getElementsByTagName(tag);
  //and a new array to hold them 
  var static_results = new Array;
  //then we just loop through and copy each into the new array 
  for (i=0; i<temp_array.length;i++) {
  static_results.push(temp_array[i]);
  }
  //and return it 
  return static_results;
  }

As a note, feel free to comment on any/all of the code articles I write here. I'm mostly writing this stuff to push my own knowledge and understanding so if you see something I can do better, something that I've missed or something that's just plain silly, feel free to let me know :)

*it WILL track the individual objects that make up the collection as those are passed to the new array as Object references.

Things to know: JavaScript Objects are copied by reference not value

I was reading PPK's excellent JavaScript book during lunch and I came across a point in his chapter on Data Types (yes, I'm reading it straight through even if I already know all the basic bits) that I think a lot of people might not understand fully. As he says:

The object data type encompasses everything that's not a number, string, or boolean. It differs from the other three types because objects are copied, passed and compared by reference, not value.

Why is that important? What does that mean? Well, consider the following HTML fragment

<div id="fruit-loops-are-fun">
<p>Fruit Loops!</p>
</div>

and a function that evaluates the following statements

var fruit_loops_div = document.getElementById("fruit-loops-are-fun");
alert(fruit_loops_div.className);

the above returns an empty alert. Empty, of course, because there's no class name associated with that named div.

nothing.png

In the same function, consider now the the next two statements

document.getElementById("fruit-loops-are-fun").className="coco-pops";
alert(fruit_loops_div.className);

that pair returns this

class.png

So, the class is set with the className attribute and, note, when it's set the original reference is used and and not the assigned variable. Even still once the class is set, the variable immediately returns the correct value.

I thought about this for a minute and came up with an interesting illustration of how a lack of understanding of this concept could have catastrophic results. WARNING, this example snippet will lock your browser up, so don't run it :)

This is based on actual work I did for Compete, by the way. I built a Wordpress plugin for them that manipulated all the links on a page in several different ways based on user preferences. In its flashiest form it added some icons that fired a Snap-like* Ajax tooltip showing Compete Snapshot data for every URL on a blog page.

In this example, instead of manipulating the links in that way I've simplified it, deciding to simply add a link after each link on the page pointing to the Compete data for the referenced domain. This is easier to follow code-wise and this it allows me to show a potential pitfall of misunderstanding the topic at hand.

Here's the death code.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  <html xmlns="http://www.w3.org/1999/xhtml">
  <head>
  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
  <title>Endless Loop</title>
  <script type="text/javascript">
  window.onload= function(){
//get all the links
  var all_links = document.getElementsByTagName("a")
 //loop through them and append a compete link
     for (i=0; i<all_links.length;i++) {
          var new_a= document.createElement("a");
          new_a.setAttribute("href","http://siteanalytics.compete.com/"+all_links[i].href);
          var new_text=document.createTextNode("snap shot data for "+all_links[i].href);
          new_a.appendChild(new_text)
          insert_after(all_links[i].parentNode,new_a,all_links[i]);
      }
  }
  function insert_after(parent, node, referenceNode) 
  {
      parent.insertBefore(node, referenceNode.nextSibling);
  }
  </script>
  </head>
  <body>
  <p><a href="http://www.drunkenfist.com/">my one link</a></p>
  </body>
  </html>

Run the above code and your browser will die after being thrown into an infinite loop. That's because the all_links nodeList isn't some sort of static snapshot of document.getElementsByTagName("a") when it's first run (which a person unfamiliar with the concepts involved might assume.) It is document.getElementsByTagName("a") and that collection grows by one every time a new link is added. Therefore, i is never less than all_links.length and your browser instance will give up the ghost. You can see a variation here (I've set a static test, so it will end after < ∞ iterations) that shows the script running out of control.

So there's what not to do :) As a foil for this browser killing code (even if it is educational) I'll write up an example of how to safely do the above operation tomorrow.

[updated]as promised, a follow-up…[/updated]
*I was actually done, or close to done with this project when the Snap plugin was released, so we weren't copying their steez…

Mad Science… Flash for a page background using JavaScript and CSS

For the current EforAll Expo*1 web site, the designer suggested that we use a flash piece for the background. It's a kind of hip event, for gamers and other technophiles so we made some assumptions about our user base and decided it was worth a go. The onus fell on me, as these things do, to set up this effect.

I'm not sure whether or not I'm proud or completely ashamed of this one. On the positive side, it was interesting to script and it looks kind of cool. On the negative it adds nothing to the site other than some pizzazz and therefore feels like a goofy script from back in the dHTML days.

I'm sure you all have your own opinions on the matter :)

Whatever side of the fence you fall on, I figured it might be interesting to explain how I got this nasty beast out the door.

My original attempt was to do it with just CSS. I envisioned some perfect voodoo combination of "overflow:hidden;", wmode=transparent and the like combining to create some magic. While I had some success, the amount of time I had to get it to work coupled with the inevitable cross browser problems, made me reconsider that approach. After a glance at the schedule and some thought I decided that if I went with a JavaScript based solution, I could be certain of implementation success and I would be able to do it in a lot less time than I had already spent on the CSS only solution.

I planned to create two DIVs, populate them with the two wings of the flash background and then set the widths of the DIVs dynamically so as to suppress any potential scroll bars. This would create the appearance of flash in the background without having to have the content sit on top of a SWF.

To start off I sketched out a skeleton of the script:

sketching-out-the-script.jpg

I then ported those steps over to Homesite as comments forming the shell of my script. I like doing that sort of preparatory work for any script that would be a new challenge for me, to make sure I have all the logic worked out before I type a single line. It doesn't always work, fo course, but it saves a lot of headaches later to have a good roadmap in place even for small scripts such as these.

In the end, I created two functions which run onload;

insert_flash() ;
set_dimensions();


set_dimensions()
also runs onresize.

insert_flash() looks like this. Comments explain the code:

function insert_flash() {
  //create a left div
           leftdiv=document.createElement("DIV")
  //give it an ID to hook JS and some styles defined in the  CSS
           leftdiv.setAttribute("id","left-bg");
  //create a right div
           rightdiv=document.createElement("DIV")
  //give it an ID to hook JS and some styles defined in the  CSS
           rightdiv.setAttribute("id","right-bg");
  //dump them into the doc at the bottom of the DOM
           document.getElementsByTagName("body")[0].appendChild(leftdiv)
           document.getElementsByTagName("body")[0].appendChild(rightdiv)                   
  //I use this totally ugly method to get the flash into the  documents. 
  //I know there are better methods. This one is so  straightforward I don't care about elegance.
           document.getElementById("left-bg").innerHTML='         <div><object  classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"  codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,19,0"  width="460" height="578"><param name="movie"  value="/themes/idg_assets/flash/bgglow_left.swf" /><param name="quality"  value="high" />; <param name="wmode"  value="transparent"><embed src="/themes/idg_assets/flash/bgglow_left.swf"  quality="high&quot  ;  wmode="transparent" pluginspage="http://www.macromedia.com/go/getflashplayer"  type="application/x-shockwave-flash" width="460"  height="578">;</embed>; </object>;</div>;';
           document.getElementById  ("right-bg").innerHTML='     <div><object  classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"  codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,19,0"  width="460" height="578"><param name="movie"  value="/themes/idg_assets/flash/bgglow_right.swf" /><param name="wmode"  value="transparent">;  <param name="quality" value="high" />;           <embed  src="/themes/idg_assets/flash/bgglow_right.swf"  quality="high"  pluginspage="http://www.macromedia.com/go/getflashplayer&quot  wmode="transparent"  type="application/x-shockwave-flash" width="460"  height="578">;</embed>; </object>;</div>;';
 }

set_dimensions looks like this. Comments again explain the code:

function set_dimensions(){
  //cross browser doc width. From ppk? I don't remember where I got this.
                 docWidth  = (typeof( window.innerWidth ) == 'number') ? docWidth = window.innerWidth :  docWidth = document.documentElement.clientWidth;
  //cross browser doc height.
                 docHeight = (typeof(  window.innerHeight ) == 'number') ? docHeight = window.innerHeight : docHeight  = document.documentElement.clientHeight;
  //if you were going to repurpose this, you would want to
  //change the following 1000 to something like
  //document.getElementById("wrapper").style.width
  //or
  //document.getElementById("wrapper").offsetWidth;
  //I just knew that the wrapper div had a width of 1000 and  just worked 
  //with that knowledge.
  //anyway, I'm just making sure we don't pass any nonsensical values  (in this case, a negative width) to the next part of the script
                if (docWidth>;1000){
  //again. We just want to make sure we pass a good value so  we parse an integer out of the diff
  //.5px doesn't really make much sense.
                     diff=parseInt((docWidth-1000)/2)
                }
                else {
                      diff=0;
                }
  //then we just set some styles
                document.getElementById("left-bg").style.width=diff+"px";
                document.getElementById("right-bg").style.width=diff+"px";
                document.getElementById("left-bg").style.height=docHeight+"px";
                document.getElementById("right-bg").style.height=docHeight+"px";
  }

The CSS looks like this:

#left-bg,
#right-bg {
width:100px;
overflow:hidden;
position:absolute;
top:0;
z-index:0;
}
/*pin the left to the left edge*/
#left-bg {
left:0;
}
/*pin the right to the right edge*/
#right-bg {
right:0;
}
#left-bg div,
#right-bg div {
position:absolute;
top:0;
z-index:0;
}
/*pin the div containing the SWF to the right edge of the left div.
This ensures the div expands the same way a centered background image would
*/
#left-bg div{
right:0;
}
/*pin the div containing the SWF to the left edge of the right div.
This ensures the div expands the same way a centered background image would
*/
#right-bg div{
left:0;
}

And that's that. It went really smoothly and it looks pretty cool across browsers (Safari, Firefox 2, IE6 an IE7). My biggest gripe about the way it looks is the way that Firefox waits until the resize event is completely over to redraw the screen. Because of that, things can look less than optimal in firefox with a dramatic browser resize. Other than that, I'm pretty happy with it (even if I'm kind of embarrassed to have written such a gratuitously useless script.)

*The site, since this article was written, has been rewritten. I'm no longer responsible for anything you see there in the way that I normally am. I tried my best to guide the site's production, but we're working with Drupal in a big way so the front end is simply out of my hands.

Javascript: getElementById() for XML fragments and arbitrary XML documents + getElementsByAttribute()

Why I never wrote this function before is a mystery.

In my experience, people* designing XML response docs for Ajax-y type applications often re-use xHMTL attributes. href and src are common examples. One other one that I've run into pretty often is id. Since Javascript's getElementById() relies on the document's DTD defining the id attribute doing something like

xml_document.getElementById('myid')

returns null when pointed at the sort of informal XML documents people often spit out for these kind of things.

To remedy that, I wrote this:

function getElementByIdMXL(the_node,the_id) {
	//get all the tags in the doc
	node_tags = the_node.getElementsByTagName('*');
	for (i=0;i<node_tags.length;i++) {
	//is there an id attribute?
		if (node_tags[i].hasAttribute('id')) {
			//if there is, test its value
			if (node_tags[i].getAttribute('id') == the_id) {
				//and return it if it matches
				return node_tags[i];
			}
		}
	}
}

where the_node is the DTD-less XML document and the_id is the id to search for. It's a pretty simple script really, but it would have been useful a couple of times in recent memory.

Looking at that bit of code made me want to create a version that searched for arbitrary attribute/value pairs. Since I've looked at getElementsByClass a thousand times it practically wrote itself:

function getElementsByAttribute(the_attribute, the_value, the_node) {
        if ( the_node == null )
             the_node = document;
        var node_tags = the_node.getElementsByTagName('*');
	var results = new Array();
	for (i=0, j=0; i<node_tags.length;i++) {
		if (node_tags[i].hasAttribute(the_attribute)) {
			if (node_tags[i].getAttribute(the_attribute) == the_value) {
			  	results[j] = node_tags[i];
            	                j++;
			}
		}
	}
	return results;
}

The only real difference between the two is the second returns an array and the first just returns the one object.

These aren't really groundbreaking, of course. They're just a couple of bits of code I thought I'd share…

*that definitely includes me

The joy of… JavaScript's getElementsByTagName()

For what it's worth the kernel of this article was dictated into my phone on my drive into work this morning. I got the idea, had the framework and figured- why the hell not just talk to myself for a while. It was actually pretty efficient, so I might do more of it and if I get good enough at this sort of extemporaneous dictation I might turn it into a podcast :)

getElementsByTagName is probably my second favorite JavaScript DOM method behind getElementById. By itself getElementsByTagName is very powerful and a combination of the two can create a powerful tool to access DOM elements anonymously. One of the core tenets in my work as a front end developer is to use semantic xHTML markup with no extraneous hooks which I then manipulate with JavaScript. I try for a clear separation between behavior, content and style, so I hate to create classes or IDs just for script. Unless an ID or Class has a real benefit in terms of CSS or has a real, valid descriptive benefit for the document in a semantic sense, I don't want to use anything other than plain vanilla HTML elements. I hate to add classes or IDs to my documents unless I absolutely have to. It's a holdover from the days when I was obsessed with bandwidth (even more than I am now) mixed with a desire to have simple, clean code.

To that end I've developed techniques to access objects and collections of objects anonymously. One of the most powerful tools in that toolbox is getElementsByTagName. I rely on it all the time.

Now, the most straightforward use of getElementsByTagName, and the one people are probably most familiar with is document.getElementsByTagName. Pass a TD or A as an argument and it will return a nodeList of all the TDs or Anchor tags in an entire document. That's great if I want to, for some reason, manipulate every DIV, A or TD on a page. The thing is, I very rarely want to manipulate every single item of a certain type on an entire page. Elements are usually used in multiple ways in a document so, what happens in that situation is there's a huge collection of elements in an array, which have to be looped through and tested for a certain class or other attribute. If I end up doing something like that, I'd rather use a a DOM helper function like getElementsByClass() or something similar. The interesting thing is, you can DOM methods and a little bit of structural markup you can get similar results as getElementsByClass() without having to create any extraneous classes.

That's because, with the way that JavaScript inheritance works, document, isn't the only object that can use the getElementsByTagName method. Any object that represents a document or document fragment (node) can provide scope to getElementsByTagName, so it's easy to limit the the search to a specific object which will represent a specific node in a document. That will then return all child nodes of that Element type of that limited document node. Say, for example, you have a DIV id of "menu". And you want to manipulate all of the LIs that sit inside of that DIV. So you’d use:

document.getElementById("menu").getElementsByTagName("li")

With that you’d get a smaller nodeList of just the child LI nodes of that "menu' DIV. That’s a really neat little collection. from there you can easily manipulate each of those to attach behaviors or to mimic the :hover pseudo class in IE6 with JavaScript or whatever else you need to do.

One other great use of getElementsByTagName is using that method on an XML node. Let’s say I'm using the XMLHttpRequest object and it returns some XML data. JavaScript recognizes that XML data as an object with nodes that you can explore and manipulate. One of the easiest ways to get at that data is to use getElementsByTagName. There are other ways to do it- using childNodes and parentNodes to iterate through the XML to test values and properties and the like is an option, but getElementsByTagName can just grab a collection of XML tags. So say there's an XML document with some arbitrary tags and the script needs to get their value.

In the XHR script the XML response to the request is set to a variable:

xml_document = http.responseXML;

then getElementsByTagName is used

xml_document.getElementsByTagName("yourtag")

which returns a collection of yourtag nodes from the XML document.

One thing I’ll often do, if I know intimately what I’m getting is pass the method a specific index. So if I know I want to get the value of the tag "city" with a name property of "Abington" and I know in advance in the XML document that represents Massachusetts cities and towns, name="Abington" is the first member of that array I can pass the 0 index to the method and return just that node. Like this:

xml_document.getElementsByTagName("city") [0]

Another thing available here is, if I set xml_document.getElementsByTagName("city") to a variable cities, I can loop through that nodeList and then again use getElementsByTagName on each member of the cities nodeList to get individual child nodes of that XML document. It’s really powerful to couple it and loop through to create these collections of collections which can be manipulated in a lot of ways.

Once common place I use getElementsByTagName is to turn a block into a clickable area. As with everything script related, I really prefer to do it anonymously. I don’t want to know in advance how many blocks there will be, what the link will be, etc. I don’t want to know any of that. I really want someone doing some markup to be able to just edit a link in HTML and then the script will come in on the backside and make the magic happen.

So there's a collection of these blocks, and a child node in each of these blocks is an anchor. A real anchor pointing to a real URL. Since, for accessibilities sake, I want to use a real link. I don’t want #s or any of that. So what I would is create a collection of LIs:

menu_lis = document.getElementById("menu").getElementsByTagName("li")

and then loop through that nodeList, using the this keyword and getElementsByTagName to reference the href property of the first A child node of each LI, to build out the JavaScript needed to make the whole block clickable

for (i=0;i< menu_lis s.length;i++) {
setHandler(menu_lis [i],'onclick','document.location=this.getElementsByTagName("a")[0].href');
}

And that's my piece on getElementsByTagName. What's next? Whatever strikes me on my drive in…

[updated to add]
I forgot to point out one use of getElementsByTagName()- using the widlcard "*" argument. Passing the wild card to the method returns a collection of every HTML element in the document. Which is useful when you want/need to flatten the hierarchy to search the elements on a page. I use it in an example script where I search through every node in an XML document testing attributes.

I like this Flash embed technique.

Assuming I don't want to do any player detection*, don't care about using the embed** tag, and just want to get the swf into the doc without IE hiccuping on it because of the Eolas patent dispute, I'm thinking this is my default Flash embed technique going forward.

This tiny bit of code gets around the "click to activate and use this control" IE issue and allows me to use traditional HTML methods to embed the SWF for browsers that didn't lose a multimillion dollar lawsuit and can just present Flash the old school way. This also allows people with Flash installed and no JavaScript to see the Flash content (I wonder how many people that actually is.)

Assuming a div with the id of "flashcontent" on the page, we run this in an included script file onload (or equivalent).


/*@cc_on @*/
/*@if (@_win32)
the_swf=document.getElemebtById("flashcontent").innerHTML
document.getElemebtById("flashcontent").innerHTML = the_swf
/*@end @*/

We use some conditional compilation to hide the script from anything but IE and then we just do a pointless switcheroo, replacing the innerHTML of the div with itself. Amazingly, that's all it takes to workaround the Eolas issue. And that's that.

Personally, I'm sold.

*for fancy stuff see the excellent swfobject.

**on the same page you can see an "object only technique" to use if getting rid of the embed tag is important

A New Site I Made Is Live…

MSLifeLines – Offering multiple sclerosis (MS) education & support

CSS, xHTML, and lots of JavaScript. The cool bits include the window shade/fade effect on the login piece at the top and a little tooltip action on the Webevents archive page. There's also some ajax-y validation + tooltip feedback on the login piece, but that's not so easy to see.

Mentioning that bit reminds me of one stupid corner I coded myself into. I was taking the server's XML response, reading one of the elements and passing the value into a variable. The element in question represented the server's response code to a login request. Being a fan of straightforward variable names I decided to call it status. I know what you're thinking. It just slipped my mind that there's already a window.status and that the two might collide. Back in the day, when everyone was scripting the hell out of the status bar, I was busy trying to do stuff that actually enhanced the user experience so I skipped out on that whole chapter of coding horror. Plus, status was a perfectly acceptable variable name for Firefox and Internet Explorer 6. It worked fine in Internet Explorer 7 with one (incredibly frustrating) exception.

During testing we were seeing errors on some IE7 installations and others worked perfectly. After much head scratching and hours of trial and error we discovered that IE7, with Medium High security has "Allow status bar updates via script" set to false. Coupling that setting with my poorly chosen variable name chucked a wrench into the heart of my script. IE7 was submitting the form correctly, parsing the data and then would run smack dab into the security wall put up by that setting. Once we discovered what was up it was an easy fix, of course, it was still a frustrating day of mystery. Next time? I'll spend just an extra second or two when naming my variables…

Don't plan around a users second visit or page view…

Instead, aim to make the first visit as good as it can be, so that there will actually be a second visit or page view.

I'll explain why I've decided to write the above (a concept I try to live by) down- One common refrain of proponents of larger JavaScript libraries is that "once the library is in cache, it doesn't matter how big the download is." I have a problem with that on two levels:

  1. Not everyone has cache turned on and many people who do have it turned on don't let files fester in there forever, so there's no guarantee the files you dump onto the user's hard drive will actually be there the next time they visit. Yahoo published some numbers on this subject in January:

    "40-60% of Yahoo!’s users have an empty cache experience and ~20% of all page views are done with an empty cache."

    To me that means relying on a user's cache to solve the problems presented by a 200k JavaScript library or 500k worth of flash or whatever isn't a proper solution.

  2. Even ignoring the above, this premise assumes a second page view or (in the case of an Ajax application) a second visit. Jakob Nielsen likes to talk about how often people use the back button and whatever you might think of him in general, he’s right about that one. On the web, unless the initial experience is positive, there will never be a second page view or visit to take advantage of the potential cached files. To that end, adding on 150-250k worth of JavaScript on top of the rest of the page where 10-50k might do just as well (in the form of either custom code or lighter libraries) just seems like a bad idea to me. Speed matters, even in this broadband era. Especially since even now there are plenty of users on slow connections. I mean, I still get around 10% of my users visiting on dialup and not every DSL/wireless connection out there is a thing of beauty.