Rosetta Code:Language comparison script: Difference between revisions

From Rosetta Code
Content added Content deleted
(Used the wrong base version for the previous modification. This one should be correct.)
(Adding some slashes to make the raw code valid JS)
Line 1: Line 1:
<lang javascript>
//<lang javascript>
/*========================================
/*========================================
This comparison script was written by
This comparison script was written by
Line 422: Line 422:
window.onload = CompareActivate;
window.onload = CompareActivate;
}
}
</lang>
//</lang>

Revision as of 20:00, 16 July 2010

//<lang javascript> /*======================================== This comparison script was written by Tyrok1, and has been tested on IE 5.5, IE 6, IE 7, IE 8, Fx 3.6.2, and Fe 4.0.280. ========================================*/ function GetElWidth(el) { return (el.clientWidth ? el.clientWidth : el.offsetWidth); }

function ToCMulticolumn() { var gutter = 10;

//split the ToC into multiple columns var tocEl = document.getElementById("toc"); var ulElsNodeList = tocEl.getElementsByTagName("ul"); if(tocEl && ulElsNodeList.length > 0) { //limit what we're looking at to only what's directly in the main list, and move from NodeList objects to Arrays var ulEls = [ulElsNodeList[0]]; for(var u = 1; u < ulElsNodeList.length; ++u) { if(ulElsNodeList[u].parentNode == ulElsNodeList[0].parentNode) { ulEls[ulEls.length] = ulElsNodeList[u]; } } var liElsNodeList = tocEl.getElementsByTagName("li"); var liEls = new Array(); for(var l = 0; l < liElsNodeList.length; ++l) { for(u = 0; u < ulEls.length; ++u) { if(liElsNodeList[l].parentNode == ulEls[u]) { liEls[liEls.length] = liElsNodeList[l]; break; } } }

//show all of the

    tags so we can get their items' ideal widths ulEls[0].oldDisplay = (ulEls[0].style.display && ulEls[0].style.display == "none" ? "none" : "inline-block"); for(u = 0; u < ulEls.length; ++u) { ulEls[u].style.display = "inline-block"; } //find the widest item and use that to set up an ideal number of columns var maxWidth = 0; for(l = 0; l < liEls.length; ++l) { if(!liEls[l].initialWidth) { liEls[l].initialWidth = GetElWidth(liEls[l]); } maxWidth = Math.max(liEls[l].initialWidth, maxWidth); if(navigator.appVersion.indexOf("MSIE 5.") >= 0 || navigator.appVersion.indexOf("MSIE 6.") >= 0 || navigator.appVersion.indexOf("MSIE 7.") >= 0) { liEls[l].style.display = "inline"; } } //add in the gutter maxWidth += gutter; //figure out the ideal number of columns tocEl.style.width = "100%"; var idealColumns = Math.min(Math.floor(GetElWidth(tocEl) / maxWidth), Math.floor(liEls.length / 3) + 1); if(navigator.appVersion.indexOf("MSIE 5.") >= 0 || navigator.appVersion.indexOf("MSIE 6.") >= 0 || navigator.appVersion.indexOf("MSIE 7.") >= 0) { idealColumns = 1; } //see if we've already got the ideal number of columns //if so, we don't need to change anything if(ulEls.length != idealColumns) { //split the list into multiple columns of width (95 / idealColumns)% //first, make sure we have enough lists to split into while(ulEls.length < idealColumns) { ulEls[ulEls.length] = ulEls[ulEls.length - 1].parentNode.insertBefore(document.createElement("ul"), ulEls[ulEls.length - 1].nextSibling); } //style the lists for(var c = 0; c < ulEls.length; ++c) { ulEls[c].style.display = "inline-block"; ulEls[c].style.cssFloat = "left"; ulEls[c].style.verticalAlign = "top"; ulEls[c].style.width = (95 / idealColumns) + "%"; } //sort the items into the lists for(l = 0; l < liEls.length; ++l) { liEls[l] = ulEls[Math.floor(l / liEls.length * idealColumns)].appendChild(liEls[l].parentNode.removeChild(liEls[l])); } //get rid of any unnecessary lists for(l = idealColumns; l < ulEls.length; ++l) { ulEls[l].parentNode.removeChild(ulEls[l]); } } //hide the instructions/lists if they're supposed to be hidden var insEl = document.getElementById("tocinstructions"); if(insEl) { insEl.style.display = (ulEls[0].oldDisplay.toLowerCase() == "none" ? "none" : "block"); } for(u = 0; u < ulEls.length; ++u) { ulEls[u].style.display = ulEls[0].oldDisplay; } //if we're setting this up for the first time... if(!window.toggleTocOld) { //change out the toggling function so it toggles all of the lists window.toggleTocOld = window.toggleToc; window.toggleUpdateVisibility = function() { var tocEl = document.getElementById("toc"); var ulEls = tocEl.getElementsByTagName("ul"); for(var u = 0; u < ulEls.length; ++u) { ulEls[u].style.display = (ulEls[0].style.display && ulEls[0].style.display == "none" ? "none" : "inline-block"); } var el = document.getElementById("tocinstructions"); if(el) { el.style.display = (ulEls[0].style.display && ulEls[0].style.display.toLowerCase() == "none" ? "none" : "block"); } }; window.toggleToc = function() { toggleTocOld(); toggleUpdateVisibility(); }; //add an event handler so if the window's resized the number of columns can change if(window.addEventListener) { window.addEventListener("resize", ToCMulticolumn, false); } else if(document.addEventListener) { document.addEventListener("resize", ToCMulticolumn, false); } else if(window.attachEvent) { window.attachEvent("onresize", ToCMulticolumn); } } } } function CompareActivate() { //check to see if we're looking at a task page var catLinksEl = document.getElementById("catlinks"); var isTask = false; if(catLinksEl) { var aEls = catLinksEl.getElementsByTagName("a"); for(var a = 0; a < aEls.length; ++a) { if(aEls[a].getAttribute("title") == "Category:Programming Tasks") { //it's a task isTask = true; break; } } } if(!isTask) { return; } //check to make sure we have a table of contents var tocEl = document.getElementById("toc"); if(tocEl) { //remove the extra show/hide button from the Contents area var tocTitleEl = document.getElementById("toctitle"); if(tocTitleEl) { var spanEls = tocTitleEl.getElementsByTagName("span"); var foundToggle = false; for(var s = 0; s < spanEls.length; ++s) { if(spanEls[s].className && spanEls[s].className.toLowerCase() == "toctoggle") { if(foundToggle) { spanEls[s].parentNode.removeChild(spanEls[s]); } foundToggle = true; } } } //find all of the links to language sections and add checkboxes var liEls = tocEl.getElementsByTagName("li"); for(var l = 0; l < liEls.length; ++l) { //add a checkbox with the language section's <a> name attribute as its value for easier lookup in the refresh function var checkboxEl = document.createElement("input"); checkboxEl.setAttribute("type", "checkbox"); checkboxEl.setAttribute("name", "CompareLanguage" + l); checkboxEl.setAttribute("id", "CompareLanguage" + l); var href = liEls[l].getElementsByTagName("a")[0].getAttribute("href"); checkboxEl.setAttribute("value", href.substring(href.indexOf("#") + 1, href.length)); checkboxEl.onclick = CompareRefresh; liEls[l].insertBefore(checkboxEl, liEls[l].firstChild); } //add some instructions var toctitleEl = document.getElementById("toctitle"); var instructionsEl = toctitleEl.appendChild(document.createElement("p")); instructionsEl.setAttribute("id", "tocinstructions"); instructionsEl.appendChild(document.createTextNode("Check the boxes next to languages to compare them.")); instructionsEl.appendChild(document.createElement("br")); instructionsEl.appendChild(document.createTextNode("Uncheck all boxes to show all languages.")); //switch the ToC to multi-column mode ToCMulticolumn(); //put all language sections inside of a

    var aEls = document.getElementsByTagName("a"); var languages = CompareGetLanguages(); var divEl = null; for(var a = 0; a < aEls.length; ++a) { if(aEls[a].name && typeof languages[aEls[a].name] != "undefined") { //we can assume that this is a language section //make a list of all of the elements between this <a> tag and the next one that has a name attribute divEl = aEls[a].parentNode.insertBefore(document.createElement("div"), aEls[a]); var curEl = aEls[a].nextSibling; divEl.appendChild(aEls[a].parentNode.removeChild(aEls[a])); while(curEl && (!curEl.tagName || curEl.tagName.toLowerCase() != "a" || !curEl.name || typeof languages[curEl.name] == "undefined")) { var newCurEl = curEl.nextSibling; divEl.appendChild(curEl.parentNode.removeChild(curEl)); curEl = newCurEl; }; } } if(divEl) { //add a float clearing div var clearEl = divEl.parentNode.insertBefore(document.createElement("div"), divEl.nextSibling); clearEl.style.clear = "both"; }

    //and refresh the display for good measure (sometimes browsers like to save <input> states between reloads) CompareRefresh();

    //add an event listener for window resizing if(window.addEventListener) { window.addEventListener("resize", CompareRefresh, false); } else if(document.addEventListener) { document.addEventListener("resize", CompareRefresh, false); } else if(window.attachEvent) { window.attachEvent("onresize", CompareRefresh); } } }

    function CompareGetLanguages() { var tocEl = document.getElementById("toc"); var languages = new Array(); if(tocEl) { //find all of the checkboxes within the ToC var inputEls = tocEl.getElementsByTagName("input"); for(var i = 0; i < inputEls.length; ++i) { //if it's one of the ones we added earlier, log the checked status to the languages array for later use if(inputEls[i].getAttribute("name").substring(0, ("CompareLanguage").length) == "CompareLanguage") { languages[inputEls[i].value] = inputEls[i].checked; } } } return languages; }

    function CompareRefresh() { //refresh the display of the language sections displayed under the ToC //first, check to see if we're looking at a task page var codeMargin = 20; var tocEl = document.getElementById("toc"); var languages = new Array(); var numChecked = 0; if(tocEl) { //count how many languages are checked languages = CompareGetLanguages(); for(var l in languages) { if(languages[l]) { ++numChecked; } }

    //now, find all <a> tags with name attributes var aEls = document.getElementsByTagName("a"); for(var a = 0; a < aEls.length; ++a) { if(aEls[a].name && typeof languages[aEls[a].name] != "undefined") { //we can assume that this is a language section //check to see if we're displaying in side-by-side mode, regular mode, or not at all if(numChecked < 1 || (languages[aEls[a].name] && (navigator.appVersion.indexOf("MSIE 5.") >= 0 || navigator.appVersion.indexOf("MSIE 6.") >= 0 || navigator.appVersion.indexOf("MSIE 7.") >= 0))) { //enable full-width mode aEls[a].parentNode.style.display = "block"; aEls[a].parentNode.style.cssFloat = "none"; aEls[a].parentNode.style.width = "auto"; aEls[a].parentNode.style.marginRight = 0; } else if(languages[aEls[a].name]) { //enable side-by-side mode aEls[a].parentNode.style.display = "inline-block"; aEls[a].parentNode.style.verticalAlign = "top"; aEls[a].parentNode.style.marginRight = "20px";

    //find the width for this language var preEls = aEls[a].parentNode.getElementsByTagName("pre"); var maxWidth = 0; for(var p = 0; p < preEls.length; ++p) { var oldWidth = GetElWidth(preEls[p]); preEls[p].style.cssFloat = "left"; if(GetElWidth(preEls[p]) == oldWidth) { //assume it's either wider than the window or IE where they don't shrink //arbitrarily set to 45% width maxWidth = Math.max(GetElWidth(aEls[a].parentNode.parentNode) * 0.45, maxWidth); } else { maxWidth = Math.max(GetElWidth(preEls[p]), maxWidth); } preEls[p].style.cssFloat = "none"; }

    //if there are no code blocks, base it off of the

    if(!maxWidth) { var h2Els = aEls[a].parentNode.getElementsByTagName("h2"); if(h2Els.length > 0) { //we have at least one h2 //use its width var oldWidth = GetElWidth(h2Els[p]); h2Els[0].style.cssFloat = "left"; if(GetElWidth(h2Els[p]) == oldWidth) { //assume it's either wider than the window or IE where they don't shrink //arbitrarily set to 45% width maxWidth = Math.max(GetElWidth(aEls[a].parentNode.parentNode) * 0.45, maxWidth); } else { maxWidth = GetElWidth(h2Els[0]); } h2Els[0].style.cssFloat = "none"; } else { //no clue what it should be //arbitrarily set it to 200 maxWidth = 200; } } //set the container
    to a size just a little bit larger

    aEls[a].parentNode.style.width = (maxWidth + codeMargin) + "px"; } else { //hide it entirely aEls[a].parentNode.style.display = "none"; } } } } }

    //register the comparison script with the window's load event if(window.addEventListener) { window.addEventListener("load", CompareActivate, false); } else if(window.attachEvent) { window.attachEvent("onload", CompareActivate); } else if(document.addEventListener) { document.addEventListener("load", CompareActivate, false); } else { window.onload = CompareActivate; } //</lang>