Whizbang.js
The whizbang.js file controls the behavior of the whizbang form and is necessary for it to operate. Here is a detailed explanation of how it all works, including a walkthrough of the javascript file.
There are a number of styled <div> tags on the WhizBang form that are hidden by default. There is a styled "list" of links that looks like a row of tabs. As you click on each tab, the related div containing that part of the form will be shown (or, if currently shown, hidden).
A second feature of the WhizBang form is query formulation. As you type or click, your query is summarized and presented on the right-hand side of the window.
If you need help modifying this system for your own needs, get in touch with us (support AT philologic DOT uchicago DOT edu).
Here is a heavily commented version of the script.
var allids = new Array();
var activeid = "none";
//allids is an array that will hold all ids of the toggleable divs
//active id is a variable to keep track of which toggleable div is currently shown
//if we have a few of these functions avaialble (i.e. we have a good, modern javascript implementation)
//then lets go ahead and use the stylesheet and start the initialization
//if we don't do this, the user will see a barebones but hopefully functional page.
if (document.getElementById && document.getElementsByTagName && document.createTextNode) {
document.write('<link rel="stylesheet" type="text/css" href="whizbang.css" />');
window.onload = initialize;
}
//the initialization function called just above.
function initialize() {
//let's check if the nav bar exists.... if not, we have no business doing anything.
var exists = eval(document.getElementById('nav'));
if (exists) {
var id;
var navbar = document.getElementById('nav');
var navlinks = navbar.getElementsByTagName('a');
//loop through all the links in the navbar
//extract the IDs of the toggleable divs from the href tags
//store those, then add on onclick to show or hide that div
//when that link is clicked.
for (var j = 0; j < navlinks.length; j++) {
allids[j] = navlinks[j].href.match(/#(\w.+)/)[1];
navlinks[j].href = "#";
navlinks[j].onclick = new Function("sshow('" + allids[j] + "');");
}
//see description of this function below
addLabelProperties();
//set up the query description area
document.getElementById("query").innerHTML = '<h2>Your query:</h2><div id="querytext">Enter search criteria to form a new search.</div>';
//add the javascript function to the reset button
document.getElementById("resetbutton").onclick = new Function ("document.forms[0].reset(); hideall(); setActiveTab('none'); formulateQuery();");
//formulate the query
hasquery = formulateQuery();
//we check to see if there is a '#' in the url (which would mean that a tab has previously
//been clicked open). if someone has been clicking the tabs, and we have some values in
//the form, let's open the tab that was last open. we only want to do that if there is
//a query and a tab has been opened before.
if (window.location.href.indexOf("#") > -1 && hasquery == true) {
activeid = GetCookie("philotab");
if (activeid) {
sshow(activeid);
}
}
}
}
//this function sets the classes of the tabs
//depending on if they are the active tab or not.
function setActiveTab(id) {
SetCookie("philotab", id);
//we set a cookie to the last active tab
//this is so when we come back to the page
//for example using the back button
//we know what tab to open if there is a query
var navlinks = document.getElementById("navlister").getElementsByTagName("li");
for (i = 0; i < navlinks.length; i++) {
if (navlinks[i].id == id + "li") {
navlinks[i].className = "activenav";
} else {
navlinks[i].className = "";
}
}
}
//this function actually makes the active tab visible
function sshow(id) {
//if the tab is already shown, hide it, and we have no active tab
if (document.getElementById(id).style.display == "block") {
hideall();
setActiveTab("none");
//otherwise, hide them all, then make the new active one visible.
//set all the classes appropraitely (isn't this done by the setActiveTab function just called?
//perhaps i am being redundant here...)
} else {
hideall();
setActiveTab(id);
var navlinks = document.getElementById("navlister").getElementsByTagName("li");
for (i = 0; i < navlinks.length; i++) {
if (navlinks[i].id == id + "li") {
navlinks[i].className = "activenav";
}
else {
navlinks[i].className = "";
}
}
//setting the display to 'block' is what makes it visible
document.getElementById(id).style.display = 'block';
// document.getElementById(id).style.border = "1px solid #242E55";
}
}
//simple function -- sets the display for the id to 'none', hiding it
function hide(id) {
document.getElementById(id).style.display = 'none';
}
//take all the ids of toggleable tabs and hide them
function hideall() {
for (var i = 0; i < allids.length; i++) {
hide(allids[i]);
}
}
//construct and show the query in the query summary div.
//this is the part you'd have to edit if you want to change
//the arrangement of the divs or add new tabs.
function formulateQuery() {
var query = "";
var subquery = "";
fieldsets = document.getElementsByTagName('fieldset');
//store all of the fieldsets in the document. make sure you are
//keep your fields in a fieldset if you want them put in the query summary
//loop through the fieldsets. for most fieldsets, we have specific ways of
//writing the query based on what's set and what the values are.
//you gotta edit this to add a new tab
for (i = 0; i < fieldsets.length; i++) {
inputs = fieldsets[i].getElementsByTagName('input');
//grab all the inputs in this fieldset.
subquery = "";
//this is an example of one of the fieldsets and how we have to construct the query
//look at each element, write out something appropriate
if (fieldsets[i].parentNode.id == "resultformat") {
if (document.getElementById("OUTPUTTF").checked) {
subquery = "Frequency by <blue>Title</blue>";
} else if (document.getElementById("kwic").checked) {
subquery = "Occurrences <blue>Line by Line [KWIC]</blue>";
} else if (document.getElementById("OUTPUTTFR").checked) {
subquery = "Frequency by <blue>Title</blue> per <blue>10,000</blue>";
} else if (document.getElementById("OUTPUTHEAD").checked) {
subquery = "Frequency by <blue>Head Object</blue>";
} else if (document.getElementById("OUTPUTAF").checked) {
subquery = "Frequency by <blue>Author</blue>";
if (document.getElementById("AFTITLEDISP").checked) {
subquery += ", <blue>(titles hidden)</blue";
}
} else if (document.getElementById("OUTPUTAFR").checked) {
subquery = "Frequency by <blue>Author</blue> per <blue>10,000</blue>";
if (document.getElementById("AFTITLEDISP").checked) {
subquery += ", <blue>(titles hidden)</blue";
}
} else if (document.getElementById("OUTPUTDF").checked || document.getElementById("OUTPUTDFR").checked) {
if (document.getElementById("OUTPUTDF").checked) {
subquery = "Frequency by <blue>Years</blue>, Year Group: ";
} else if (document.getElementById("OUTPUTDFR").checked) {
subquery = "Frequency by <blue>Years</blue>, per <blue>10,000</blue>, Year Group: ";
}
subquery += "<blue>" + document.getElementById("DFPERIOD").options[document.getElementById("DFPERIOD").selectedIndex].text + "</blue>";
if (document.getElementById("DFTITLEDISP").checked) {
subquery += " <blue>(titles hidden)</blue";
}
} else if (document.getElementById("OUTPUTPF").checked) {
subquery = "<blue>Collocation Table</blue> Spanning ";
subquery += "<blue>" + document.getElementById("POLESPAN").options[document.getElementById("POLESPAN").selectedIndex].text + "</blue> words";
if (document.getElementById("POLEFILTER").checked) {
subquery += ", <blue>(filter off)</blue";
}
} else if (document.getElementById("OUTPUTTR").checked) {
subquery = "<blue>Theme-Rheme</blue> Display: ";
subquery += "<blue>" + document.getElementById("THMPRTLIMIT").options[document.getElementById("THMPRTLIMIT").selectedIndex].text + "</blue>";
} else if (document.getElementById("TRSORT").checked) {
subquery = "Sort by <blue>bibliography</blue>, Order by: ";
subquery += "<blue>" + document.getElementById("trsortorder").options[document.getElementById("trsortorder").selectedIndex].text + "</blue>";
} else if (document.getElementById("OUTPUTSK").checked) {
subquery = "<blue>KWIC sort by keyword</blue> and word to its ";
subquery += "<blue>" + document.getElementById("KWSS").options[document.getElementById("KWSS").selectedIndex].text + "</blue>, Display up to ";
subquery += "<blue>" + document.getElementById("KWSSPRLIM").options[document.getElementById("KWSSPRLIM").selectedIndex].text + "</blue> occurrences";
}
} else if (fieldsets[i].parentNode.id == "searchopt") {
if (document.getElementById("conjpro").checked) {
subquery = "Phrase separated by <blue>" + document.getElementById("phrasedistance").value + "</blue> words";
} else if (document.getElementById("cj6").checked) {
subquery = "Proximity Searching in the <blue>Same Sentence</blue>"
} else if (document.getElementById("cj5").checked) {
subquery = "Proximity Searching in the <blue>Same Paragraph</blue>";
}
//we skip main bib.... that is taken care of under bibliographic
//for the others, we just use the names on the labels and the values to make a simple
//writeup
} else if (fieldsets[i].parentNode.id != "mainbib") {
for(j = 0; j < inputs.length; j++) {
if (inputs[j].value != '' && inputs[j].type == "text" && inputs[j].value != "Terms") {
subquery += inputs[j].label + " <blue>'" + inputs[j].value + "'</blue>, ";
}
}
if (fieldsets[i].parentNode.id == "bibfields") {
inputs = document.getElementById('mainbibfs').getElementsByTagName('input');
for(j = 0; j < inputs.length; j++) {
if (inputs[j].value != '' && inputs[j].type == "text" && inputs[j].value != "Terms") {
subquery += inputs[j].label + " <blue>'" + inputs[j].value + "'</blue>, ";
}
}
}
}
//if we found something in this fieldset, we add it to the main query
//with some specific extras if certain things are certain ways...
if (subquery != "") {
//if there is something in the main search input, and the similarity search is on, say so
if (fieldsets[i].parentNode.id == "basicform") {
if (document.getElementById("etsim").checked) {
subquery += " and <blue>similar words</blue>";
}
//if we have bibliographic stuff, show the bibsort options
} else if (fieldsets[i].parentNode.id == "bibfields") {
subquery += "sort by <blue>" + document.getElementById("sortorder").options[document.getElementById("sortorder").selectedIndex].text + "</blue>";
}
//kill trailing spaces
subquery = subquery.replace(/,\s$/, "");
//don't link maincontents, otherwise make a link to show that tab's visibility
if (fieldsets[i].parentNode.id != "maincontents") {
//query += "<a href='#" + fieldsets[i].parentNode.id + "' onClick='show(this);' >" + fieldsets[i].title + "</a>: " + subquery + "<br>";
query += "<a href='javascript:sshow(\"" + fieldsets[i].parentNode.id + "\")'>" + fieldsets[i].title + "</a>: " + subquery + "<br>";
} else {
query += "<b>" + fieldsets[i].title + "</b>: " + subquery + "<br>";
}
}
}
//no query? ok, show the default
if (query == "") {
document.getElementById("querytext").innerHTML = "Enter search criteria to form a new search.";
return false;
//otherwise, show the query.
} else {
document.getElementById("querytext").innerHTML = query;
return true;
}
}
//for each labeled input, we need to add an appropriate handler to
//update the query when that value changes
function addLabelProperties() {
if ( typeof document.getElementsByTagName == 'undefined' ) return;
var labels = document.getElementsByTagName( "label" );
var label, i = j = 0;
var elem;
while ( label = labels[i++] ) {
if ( typeof label.htmlFor == 'undefined' ) return;
elem = document.getElementById(label.htmlFor);
if ( typeof elem == 'undefined' ) {
self.devError( [label.htmlFor], 'noLabel' );
} else if ( typeof elem.length != 'undefined' && elem.length > 1 && elem.nodeName != 'SELECT' ) {
for ( j = 0; j < elem.length; j++ ) {
elem.item( j ).label = label;
}
}
elem.label = label.innerHTML;
if (elem.type == "text" ) {
elem.onkeyup = function () { formulateQuery() };
} else if (elem.type == "radio" || elem.type == "checkbox") {
elem.onclick = function () { formulateQuery() };
} else if (elem.type == "select-one") {
elem.onchange = function () { formulateQuery(); };
}
}
}