HTML Dog

Skip to navigation

Suckerfish Shoal

By Patrick Griffiths and Dan Webb.

Now we've come up with a whole load of variants on the original Suckerfish this humble little perch is beginning to turn into a bit of a monster. If we want to use more than one Suckerfish function at a time, we need to do it in a way that ensures all of these Suckerfishes swim together nicely on the page without upsetting each other's operation and without having to repeat code unnecessarily. You can obviously do this a number of ways, but here's one solution, cunningly called the Suckerfish Shoal.

The Suckerfish Shoal allows us to apply Suckerfish behaviour to pages in a modular fashion so that you may only include the functions you need to minimise the file size of the HTML or JavaScript file. Further to this, the shoal provides an easy framework for you to write your own Suckerfish-like functions to patch over IE's lack of standards compliance. Obviously, there's a lot that can be patched so the possibilities are huge.

Also, the Suckerfish Shoal allows much more flexibility in what elements you apply the behaviour to. This is important when using a lot of Suckerfish behaviours on your page as narrowing the number of elements the Suckerfish operates on will minimise rendering time.

Right then, sod it, let's just jump in at the deep end first and then we'll explain how to swim. Here's the code (take a deep breath!):


function suckerfish(type, tag, parentId) {
	if (window.attachEvent) {
		window.attachEvent("onload", function() {
			var sfEls = (parentId==null)?document.getElementsByTagName(tag):document.getElementById(parentId).getElementsByTagName(tag);
			type(sfEls);
		});
	}
}

sfHover = function(sfEls) {
	for (var i=0; i<sfEls.length; i++) {
		sfEls[i].onmouseover=function() {
			this.className+=" sfhover";
		}
		sfEls[i].onmouseout=function() {
			this.className=this.className.replace(new RegExp(" sfhover\\b"), "");
		}
	}
}

sfFocus = function(sfEls) {
	for (var i=0; i<sfEls.length; i++) {
		sfEls[i].onfocus=function() {
			this.className+=" sffocus";
		}
		sfEls[i].onblur=function() {
			this.className=this.className.replace(new RegExp(" sffocus\\b"), "");
		}
	}
}

sfActive = function(sfEls) {
	for (var i=0; i<sfEls.length; i++) {
		sfEls[i].onmousedown=function() {
			this.className+=" sfactive";
		}
		sfEls[i].onmouseup=function() {
			this.className=this.className.replace(new RegExp(" sfactive\\b"), "");
		}
	}
}

sfTarget = function(sfEls) {
	var aEls = document.getElementsByTagName("A");
	document.lastTarget = null;
	for (var i=0; i<sfEls.length; i++) {
		if (sfEls[i].id) {
			if (location.hash==("#" + sfEls[i].id)) {
				sfEls[i].className+=" sftarget";
				document.lastTarget=sfEls[i];
			}
			for (var j=0; j<aEls.length; j++) {
				if (aEls[j].hash==("#" + sfEls[i].id)) aEls[j].targetEl = sfEls[i];
				aEls[j].onclick = function() {
					if (document.lastTarget) docu.lastTarget.className = document.lastTarget.className.replace(new RegExp(" sftarget\\b"), "");
					if (this.targetEl) this.targetEl.className+=" sftarget";
					document.lastTarget=this.targetEl;
					return true;
				}
			}
		}
	}
}

The initial suckerfish() function takes a Suckerfish function name, a tag you want to apply the behaviour to and optionally, a parent element id. So, for example, if you wanted to apply Suckerfish :hover to all of the list elements inside the element 'nav' (As in the Suckerfish :hover and Son of Suckerfish Dropdowns examples) you'd do this:


suckerfish(sfHover, "LI", "nav");

As another example, if you wanted to add the Suckerfish :focus to all input elements and textarea elements you would do this:


suckerfish(sfFocus, "INPUT");
suckerfish(sfFocus, "TEXTAREA");

As you can see, it allows us far more flexibility that manually changing the var sfEls... line of the independent Suckerfish functions.

You will probably have noticed that the code for the specific Suckerfish functions are more or less identical to the standalone versions. Because these 'modules' are independent of each other, you can simply pull out the ones that you don't want to use (and you probably won't want to use all of them), leaving you with a streamlined solution.

Examples

In all likelihood, you won't want to use every Suckerfish under the sun, but you could if you really wanted to.