User:Bp/interactive tree script

I, and others, didn't like the scroll boxes used to shorten the "Appearances" and "References" sections. User:Cid Highwind proposed a way to hide the sections until the user selected to show them (see Forum:Appearances section - suggestion), and I took this idea a little further and wrote a script that allows the trees that contain this information to be collapsed and expanded, while also counting the sub-items so that some meaningful information is immediately available.

Originally, I wrote this to be used only for appearances, but it can be used for other trees as well.

Usage
To use the script, enclose the tree with: 
 * Item
 * Item
 * Item
 * Item
 * Item
 * Item

The class can be used with other classes, like. There is another special class,, which will not add a count of the sub-items to the end of the branches.

Tweaks
If you don't want the script to run, add this line to your User:/monobook.js: interactiveTrees = 0;

If you want to have the scroll boxes, add this line to your User:/monobook.css: .appear{ overflow:auto; height:230px; width:75%; float:left; }

To set the minum number of leaves that can be left open, add this line to your User:/monobook.css: (n is the number of leaves) smallTreeCount = ;

To set the string of text that appears at the top of counted lists, add this line to your User:/monobook.css: (put  where you want the number to appear) descriptionString = " ";

Example
{| width="100%" ! Interactive ! Non-interactive (source)
 * width="50%" valign="top" |
 * width="50%" valign="top" |

Pakled appearances

 * A person wearing a Pakled costume can be seen in the bar on Ronara Prime in, however, they lack the Pakled-make-up.
 * (background extras)
 * A person wearing a Pakled costume can be seen in the bar on Ronara Prime in, however, they lack the Pakled-make-up.
 * (background extras)

Q appearances



 * width="50%" valign="top" |

Guy Vardaman appearances as Darien Wallace

 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }
 * }

Issues

 * If the user has a languge other than English set in his preferences, the wiki software will serve him Mediawiki:Monobook.js/[that language]. I imagine this is so that the scripts can be multi-language, for example this script might have a different label instead of the English "This list contains %s items." Unfortunately there is no Common.js as there is with Common.css, the script would need to be copied into each language's sub-page. A workaround is being investigated.

Source
The source for the version running on MA is in Mediawiki:common.css and Mediawiki:common.js.

Versions

 * rev 4
 * made the script work nicely with multiple classes
 * added "nocount" class
 * rev 3
 * Fix a bug noticed by User:Renegade54 where the shortening of the page after it is reformated could cause it to lose the place of the named anchor
 * reverted and re-revised (with help from User:Splarka):
 * Firefox fires an onload event when window.location = window.location.hash; So, tried it a different way.
 * Fixed a bug in Safari where the control links were invisible. Safari still has the bug Renegade54 mentioned, because Safari is not very smart. It returns the # with window.location.hash, but it believes that it is part of the bookmark name if you use it.
 * rev 2
 * Changed the label from "%d appearances." to "This list contains %d items." so that the script can be used for other trees besides appearances.
 * Now includes ordered lists (  ) in the tree
 * var smallTreeCount now holds the limit number of leaves that cause the tree to be completely visible by default, so it can be set by users in User:/monobook.js
 * rev 1
 * Removed a debug function that I used while writing, but doesn't do anything on MA
 * first release
 * First time uploaded

CSS
.hiddenlist { display:none; } .visiblelist { display:block; }

.listexpand { text-decoration: none; color: #66BBFF; } .listexpand:hover { text-decoration: underline; color: #66BBFF; }

JS
// Start "Hidden appearances section/interactive tree" script; by User:Bp // - function toggleAppearancesPane(eid) { e = document.getElementById(eid); if (e) { e.className = (e.className == "hiddenlist") ? "visiblelist" : "hiddenlist"; } }

function showAppearancesPane(eid) { e = document.getElementById(eid); if (e) { e.className = "visiblelist"; } }

function hideAppearancesPane(eid) { e = document.getElementById(eid); if (e) { e.className = "hiddenlist"; } } // -

var tree = 0; var pane = 0; var paneListForThisTree = new Array; var descriptionString = new String("This list contains %d items."); //%d is where the number of items is inserted

var smallTreeCount = 8; // less leaves than this, the tree will be open at first var interactiveTrees = 1; // set this to 0 in user.js to turn this off

function button(text,onclick,cls) { var b = document.createElement('a'); b.innerHTML = text; b.href="javascript:"+onclick; b.className = cls; return b; }

function recursiveCountAndMark(e, depth, nocount) { var si = e.firstChild; var total = 0; while(si) { var tn = (si.tagName) ? si.tagName.toLowerCase : ''; if (tn == "li") { total++; } var subtotal = recursiveCountAndMark(si, depth+1, nocount); if (tn == "ul" || tn == "ol") { if (depth > 1) { si.id = "Pane" + pane++; paneListForThisTree.push(si.id); si.className = "hiddenlist";

si.parentNode.insertBefore(document.createTextNode('('), si);				si.parentNode.insertBefore(button( (nocount) ? "+/-" : subtotal, "toggleAppearancesPane(\""+si.id+"\")", "listexpand"), si);				si.parentNode.insertBefore(document.createTextNode(')'), si); total--; // don't count the li that this ul/ol is in			} else { // we are finished and this is the top ul/ol if (subtotal < smallTreeCount) { // this small enough they can be visible right away for (var i=0;i<paneListForThisTree.length;i++) { toggleAppearancesPane(paneListForThisTree[i]); }				}				var allonexec = '{'; var alloffexec = '{'; for (var i=0;i<paneListForThisTree.length;i++) { allonexec += "showAppearancesPane(\""+paneListForThisTree[i]+"\"); "; alloffexec += "hideAppearancesPane(\""+paneListForThisTree[i]+"\"); "; }				allonexec += '}'; alloffexec += '}';

var ds = (nocount) ? "" : descriptionString.replace(/\%d/g, subtotal);

si.parentNode.insertBefore(document.createTextNode(ds + ' ('), si);				si.parentNode.insertBefore(button("show all", allonexec, "listexpand"), si);				si.parentNode.insertBefore(document.createTextNode(' | '), si);				si.parentNode.insertBefore(button("hide all", alloffexec, "listexpand"), si);				si.parentNode.insertBefore(document.createTextNode(')'), si); }		}		total += subtotal; si = si.nextSibling; }	return total; }

function doAppearancesTrees { if (!interactiveTrees) { return; }

var divs = document.getElementsByTagName("div"); for (var i = 0; i < divs.length; i++) { if (divs[i].className.match(/\bappear\b/)) { recursiveCountAndMark(divs[i], 0, (divs[i].className.match(/\bnocount\b/)) ? 1 : 0); paneListForThisTree = new Array; tree++; }	}

// fix a bug noticed by renegade54 // jump to the named anchor again if (window.location.hash && tree > 0) { // still won't work 100% in safari and khtml if (navigator.userAgent.indexOf("MSIE") != -1) { window.location = window.location.hash; // -- causes Firefox to fire onload events } else { window.location.hash = window.location.hash; }	}

}

hookEvent("load", doAppearancesTrees);

On other wikis
A couple people asked to use it one their wikis, which is nice. I'm glad it's useful to someone. As I explained to them, it is CC-by-nc 2.5, like all of MA, so most wiki's that are GFDL or GPL or whatever need to make that explicit, and comply. Also, tell me so I can put it on the list.


 * The X-Files Wiki
 * The Muppet Wiki
 * The Farscape Wiki
 * Dollhouse Wiki
 * The Bill Wiki