Skip to content

Instantly share code, notes, and snippets.

@6174
Created March 8, 2014 09:27
Show Gist options
  • Save 6174/9427815 to your computer and use it in GitHub Desktop.
Save 6174/9427815 to your computer and use it in GitHub Desktop.
collapsiblelists.js
/*
CollapsibleLists.js
An object allowing lists to dynamically expand and collapse
Created by Stephen Morley - http://code.stephenmorley.org/ - and released under
the terms of the CC0 1.0 Universal legal code:
http://creativecommons.org/publicdomain/zero/1.0/legalcode
*/
// create the CollapsibleLists object
var CollapsibleLists =
new function(){
/* Makes all lists with the class 'collapsibleList' collapsible. The
* parameter is:
*
* doNotRecurse - true if sub-lists should not be made collapsible
*/
this.apply = function(doNotRecurse){
// loop over the unordered lists
var uls = document.getElementsByTagName('ul');
for (var index = 0; index < uls.length; index ++){
// check whether this list should be made collapsible
if (uls[index].className.match(/(^| )collapsibleList( |$)/)){
// make this list collapsible
this.applyTo(uls[index], true);
// check whether sub-lists should also be made collapsible
if (!doNotRecurse){
// add the collapsibleList class to the sub-lists
var subUls = uls[index].getElementsByTagName('ul');
for (var subIndex = 0; subIndex < subUls.length; subIndex ++){
subUls[subIndex].className += ' collapsibleList';
}
}
}
}
};
/* Makes the specified list collapsible. The parameters are:
*
* node - the list element
* doNotRecurse - true if sub-lists should not be made collapsible
*/
this.applyTo = function(node, doNotRecurse){
// loop over the list items within this node
var lis = node.getElementsByTagName('li');
for (var index = 0; index < lis.length; index ++){
// check whether this list item should be collapsible
if (!doNotRecurse || node == lis[index].parentNode){
// prevent text from being selected unintentionally
if (lis[index].addEventListener){
lis[index].addEventListener(
'mousedown', function (e){ e.preventDefault(); }, false);
}else{
lis[index].attachEvent(
'onselectstart', function(){ event.returnValue = false; });
}
// add the click listener
if (lis[index].addEventListener){
lis[index].addEventListener(
'click', createClickListener(lis[index]), false);
}else{
lis[index].attachEvent(
'onclick', createClickListener(lis[index]));
}
// close the unordered lists within this list item
toggle(lis[index]);
}
}
};
/* Returns a function that toggles the display status of any unordered
* list elements within the specified node. The parameter is:
*
* node - the node containing the unordered list elements
*/
function createClickListener(node){
// return the function
return function(e){
// ensure the event object is defined
if (!e) e = window.event;
// find the list item containing the target of the event
var li = (e.target ? e.target : e.srcElement);
while (li.nodeName != 'LI') li = li.parentNode;
// toggle the state of the node if it was the target of the event
if (li == node) toggle(node);
};
}
/* Opens or closes the unordered list elements directly within the
* specified node. The parameter is:
*
* node - the node containing the unordered list elements
*/
function toggle(node){
// determine whether to open or close the unordered lists
var open = node.className.match(/(^| )collapsibleListClosed( |$)/);
// loop over the unordered list elements with the node
var uls = node.getElementsByTagName('ul');
for (var index = 0; index < uls.length; index ++){
// find the parent list item of this unordered list
var li = uls[index];
while (li.nodeName != 'LI') li = li.parentNode;
// style the unordered list if it is directly within this node
if (li == node) uls[index].style.display = (open ? 'block' : 'none');
}
// remove the current class from the node
node.className =
node.className.replace(
/(^| )collapsibleList(Open|Closed)( |$)/, '');
// if the node contains unordered lists, set its class
if (uls.length > 0){
node.className += ' collapsibleList' + (open ? 'Open' : 'Closed');
}
}
}();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment