In the the words of its developer, PureDOM Explorer (PDE) provides “explorer-style navigation” to lists turning them into expandable and collapsible tree structures. In 2009, I was tasked with adding functionality to a list utilizing this script. I’ve just stumbled across it and decided to share.

The PDE script that supplied the expand/collapse functionality seems to work so well that it’s been left as-is. Our application required that the individual nodes be selectable via checkboxes. This idea implied the following logic:

  • If checked and the parent LI’s UL is nested then also check the necessary parent UL nodes while excluding their children
  • If checked and is a “folder” then check all children, including all nested UL’s and their children
  • If unchecked and is a “folder” then deselect all child LI’s and nested “folder” li’s
  • If unchecked and is not a top-level “folder” then merely uncheck that element

I won’t get into implementing PDE as its developer does that sufficiently enough. The add-on that I wrote to do the checking/unchecking of check boxes merely requires that an onClick event be added to all of the checkboxes. Please feel free to delegate the events instead of adding them inline – remember, I wrote this in ’09!

As an aside, I’m sure that this will work on any list that is structured the same as the example regardless of PDE’s presence.

Below is an example: Expand the tree and select / deselect the nodes and notice how the corresponding parents and children are correctly checked/unchecked.

Here’s the toggle code:

function toggle(obj){
	var cL = new Array(); // child list, UL's
	
	// toggle all checkboxes
	if (obj.parentNode.tagName == 'LI' && obj.parentNode.childNodes.length != 0){
		var pNode = obj.parentNode;
		for (i=0;i<pNode.childNodes.length;i++){
			if (pNode.childNodes[i].tagName == 'UL'){
				cL[0] = pNode.childNodes[i];
				break;
			}
		}
	}
	if (cL.length != 0 ){
		for (j=0;j<cL.length;j++){
			if (cL[j].childNodes.length != 0){
				for (h=0;h<cL[j].childNodes.length;h++){
					if (cL[j].childNodes[h].tagName == 'LI'){
						for (r=0;r<cL[j].childNodes[h].childNodes.length;r++){
							if (cL[j].childNodes[h].childNodes[r].tagName == 'UL'){
								cL[cL.length] = cL[j].childNodes[h].childNodes[r];
							}
						}
					}
				}
			}
		}
		for (q=0;q<cL.length;q++){
			for (w=0;w<cL[q].childNodes.length;w++){
				if (cL[q].childNodes[w].tagName != undefined){
					for (e=0;e<cL[q].childNodes[w].childNodes.length;e++){
						if (cL[q].childNodes[w].childNodes[e].tagName != undefined && cL[q].childNodes[w].childNodes[e].type == 'checkbox'){
							cL[q].childNodes[w].childNodes[e].checked = !obj.checked ? false:true;
						}
					}
				}
			}
		}
	}
	var pL = new Array(obj.parentNode.parentNode.parentNode);
	if (pL[0].tagName == 'LI'){
		for (qq=0;qq<pL.length;qq++){
			if (pL[qq].tagName == 'LI' && pL[qq].parentNode.parentNode.tagName == 'LI'){
				pL[pL.length] = pL[qq].parentNode.parentNode;
			}
		}
		for (ww=0;ww<pL.length;ww++){
			for (ee=0;ee<pL[ww].childNodes.length;ee++){
				if (pL[ww].childNodes[ee].type == 'checkbox'){
					pL[ww].childNodes[ee].checked = true;
				}
			}
		}
	}
}