User:Tyrok1/monobook.js: Difference between revisions
Content added Content deleted
(Attempting to force columns to contain a minimum of three primary language sections.) |
(Testing the per-code example buttonbar) |
||
Line 1: | Line 1: | ||
/*======================================== |
/*======================================== |
||
This comparison script was written by |
This comparison script was written by |
||
Tyrok1, and has been tested on IE |
Tyrok1, and has been tested on IE 7, |
||
IE 8, Fx 3.6.3, and Fe 5.0.380. |
|||
Fe 4.0.280. |
|||
========================================*/ |
========================================*/ |
||
function GetElWidth(el) |
|||
//define the relationship between the CSS classes and the language names |
|||
var buttonBarCodepadLanguages = [ |
|||
{ cssClass: "c", padName: "C" }, |
|||
{ cssClass: "cpp", padName: "C++" }, |
|||
{ cssClass: "d", padName: "D" }, |
|||
{ cssClass: "haskell", padName: "Haskell" }, |
|||
{ cssClass: "lua", padName: "Lua" }, |
|||
{ cssClass: "ocaml", padName: "OCaml" }, |
|||
{ cssClass: "php", padName: "PHP" }, |
|||
{ cssClass: "perl", padName: "Perl" }, |
|||
{ cssClass: "python", padName: "Python" }, |
|||
{ cssClass: "ruby", padName: "Ruby" }, |
|||
{ cssClass: "scheme", padName: "Scheme" }, |
|||
{ cssClass: "tcl", padName: "Tcl" } |
|||
]; |
|||
function AddHandler(el, handlerType, func) |
|||
{ |
{ |
||
//add an event handler in a more cross-browser way |
|||
return (el.clientWidth ? el.clientWidth : el.offsetWidth); |
|||
if(el.addEventListener) |
|||
{ |
|||
el.addEventListener(handlerType, func, false); |
|||
} |
|||
else if(el.attachEvent) |
|||
{ |
|||
el.attachEvent("on" + handlerType, func); |
|||
} |
|||
else |
|||
{ |
|||
eval("el.on" + handlerType + " = func;"); |
|||
} |
|||
} |
} |
||
function |
function IsChild(parent, child) |
||
{ |
{ |
||
//check to see if an element is a child of another element |
|||
var gutter = 10; |
|||
while(child && child != parent) |
|||
//split the ToC into multiple columns |
|||
var tocEl = document.getElementById("toc"); |
|||
var ulElsNodeList = tocEl.getElementsByTagName("ul"); |
|||
if(tocEl && ulElsNodeList.length > 0) |
|||
{ |
{ |
||
child = child.parentNode; |
|||
//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]]; |
|||
return (child == parent); |
|||
for(var u = 1; u < ulElsNodeList.length; ++u) |
|||
} |
|||
function ButtonBarSelectAll(preEl) |
|||
{ |
|||
//select all code within a given <pre> element |
|||
var range = null; |
|||
var menuEl = preEl.getElementsByTagName("ul")[0]; |
|||
if(((document.createRange && (range = document.createRange())) || (document.selection.createRange && (range = document.selection.createRange()))) && range.selectNodeContents) |
|||
{ |
|||
//for Fx, Fe, and other more standards-compliant browsers |
|||
range.selectNodeContents(preEl); |
|||
range.setEndBefore(menuEl); |
|||
var sel = window.getSelection(); |
|||
if(sel.setBaseAndExtent) |
|||
{ |
{ |
||
//odd variant of a few of the WebKit browsers |
|||
if(ulElsNodeList[u].parentNode == ulElsNodeList[0].parentNode) |
|||
sel.setBaseAndExtent(preEl, 0, menuEl, 0); |
|||
{ |
|||
ulEls[ulEls.length] = ulElsNodeList[u]; |
|||
} |
|||
} |
} |
||
else |
|||
var liElsNodeList = tocEl.getElementsByTagName("li"); |
|||
var liEls = new Array(); |
|||
for(var l = 0; l < liElsNodeList.length; ++l) |
|||
{ |
{ |
||
sel.removeAllRanges(); |
|||
for(u = 0; u < ulEls.length; ++u) |
|||
sel.addRange(range); |
|||
{ |
|||
if(liElsNodeList[l].parentNode == ulEls[u]) |
|||
{ |
|||
liEls[liEls.length] = liElsNodeList[l]; |
|||
break; |
|||
} |
|||
} |
|||
} |
} |
||
} |
|||
else |
|||
{ |
|||
//for IE |
|||
range = document.body.createTextRange(); |
|||
range.moveToElementText(preEl); |
|||
var menuRange = document.body.createTextRange(); |
|||
menuRange.moveToElementText(menuEl); |
|||
//deselect the popup menu |
|||
//show all of the <ul> tags so we can get their items' ideal widths |
|||
while(range.compareEndPoints("EndToStart", menuRange) > 0) |
|||
ulEls[0].oldDisplay = (ulEls[0].style.display && ulEls[0].style.display == "none" ? "none" : "inline-block"); |
|||
for(u = 0; u < ulEls.length; ++u) |
|||
{ |
{ |
||
range.moveEnd("word", -1); |
|||
ulEls[u].style.display = "inline-block"; |
|||
} |
} |
||
range.select(); |
|||
} |
|||
//find the widest item and use that to set up an ideal number of columns |
|||
var maxWidth = 0; |
|||
//return the range so other functions can use it |
|||
for(l = 0; l < liEls.length; ++l) |
|||
return range; |
|||
} |
|||
function ButtonBarCreateSelectAll(preEl) |
|||
{ |
|||
return function() { |
|||
//select all of the text in the pre element |
|||
ButtonBarSelectAll(preEl); |
|||
}; |
|||
} |
|||
function ButtonBarCreateCopy(preEl) |
|||
{ |
|||
return function() { |
|||
//copy all of the text in the pre element |
|||
//IE-only at this point |
|||
var range = ButtonBarSelectAll(preEl); |
|||
range.execCommand("Copy"); |
|||
}; |
|||
} |
|||
function ButtonBarGetText(preEl) |
|||
{ |
|||
//get the code from inside of a <pre> element |
|||
var outText = ""; |
|||
for(var c = 0; c < preEl.childNodes.length; ++c) |
|||
{ |
|||
switch(preEl.childNodes[c].tagName ? preEl.childNodes[c].tagName.toLowerCase() : "") |
|||
{ |
{ |
||
case "br": |
|||
if(!liEls[l].initialWidth) |
|||
{ |
{ |
||
outText += "\n"; |
|||
liEls[l].initialWidth = GetElWidth(liEls[l]); |
|||
} |
} break; |
||
case "ul": |
|||
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) |
|||
{ |
{ |
||
//get rid of s |
|||
liEls[l].style.display = "inline"; |
|||
outText = outText.replace(/\xA0/g, " "); |
|||
//return the cleaned text |
|||
return outText; |
|||
} break; |
|||
default: |
|||
{ |
|||
outText += (preEl.childNodes[c].textContent ? preEl.childNodes[c].textContent : (preEl.childNodes[c].innerText ? preEl.childNodes[c].innerText : preEl.childNodes[c].data)); |
|||
} |
} |
||
} |
} |
||
} |
|||
//add in the gutter |
|||
//get rid of s |
|||
maxWidth += gutter; |
|||
outText = outText.replace(/\xA0/g, " "); |
|||
//figure out the ideal number of columns |
|||
//return the cleaned text |
|||
tocEl.style.width = "100%"; |
|||
return outText; |
|||
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) |
|||
{ |
|||
function ButtonBarAddSpacer(ulEl) |
|||
idealColumns = 1; |
|||
{ |
|||
} |
|||
//add a spacer bullet item to the menu list |
|||
var spacerEl = ulEl.appendChild(document.createElement("li")); |
|||
//see if we've already got the ideal number of columns |
|||
spacerEl.appendChild(document.createTextNode("\u2022")); |
|||
//if so, we don't need to change anything |
|||
spacerEl.style.display = "inline"; |
|||
if(ulEls.length != idealColumns) |
|||
spacerEl.style.marginLeft = "0.5em"; |
|||
{ |
|||
spacerEl.style.marginRight = "0.5em"; |
|||
//split the list into multiple columns of width (95 / idealColumns)% |
|||
} |
|||
//first, make sure we have enough lists to split into |
|||
while(ulEls.length < idealColumns) |
|||
function ButtonBarCreateMouseOver(preEl) |
|||
{ |
|||
//the mouseover event handler for <pre> elements |
|||
return function() { |
|||
//if there's already a menu, don't add another |
|||
if(preEl.getElementsByTagName("ul").length > 0) |
|||
{ |
|||
return false; |
|||
} |
|||
//style the <pre> and add the menu |
|||
preEl.style.position = "relative"; |
|||
var ulEl = preEl.appendChild(document.createElement("ul")); |
|||
ulEl.className = "ButtonBar"; |
|||
ulEl.style.position = "absolute"; |
|||
ulEl.style.right = 0; |
|||
ulEl.style.top = 0; |
|||
ulEl.style.whitespace = "nowrap"; |
|||
ulEl.style.marginRight = "0.5em"; |
|||
//define actions we want to add |
|||
var listItems = [ |
|||
{title:"Select All",code:ButtonBarCreateSelectAll(preEl)} |
|||
]; |
|||
if(window.clipboardData) |
|||
{ |
|||
listItems[listItems.length] = {title:"Copy to Clipboard",code:ButtonBarCreateCopy(preEl)}; |
|||
} |
|||
//add the standard menu items |
|||
for(var i = 0; i < listItems.length; ++i) |
|||
{ |
|||
//if it's not the first one, add a spacer |
|||
if(i > 0) |
|||
{ |
|||
ButtonBarAddSpacer(ulEl); |
|||
} |
|||
var liEl = ulEl.appendChild(document.createElement("li")); |
|||
liEl.appendChild(document.createTextNode(listItems[i].title)); |
|||
liEl.style.cursor = "pointer"; |
|||
liEl.style.display = "inline"; |
|||
liEl.style.fontFamily = "sans-serif"; |
|||
liEl.style.textDecoration = "underline"; |
|||
AddHandler(liEl, "click", listItems[i].code); |
|||
} |
|||
//check for a codepad-supported language |
|||
var langClass = preEl.className.split(" ")[0]; |
|||
for(var l = 0; l < buttonBarCodepadLanguages.length; ++l) |
|||
{ |
|||
if(langClass == buttonBarCodepadLanguages[l].cssClass) |
|||
{ |
|||
//found the language |
|||
//add <li>s |
|||
ButtonBarAddSpacer(ulEl); |
|||
var liEl = ulEl.appendChild(document.createElement("li")); |
|||
liEl.style.display = "inline"; |
|||
//build a form to submit to codepad |
|||
var formEl = liEl.appendChild(document.createElement("form")); |
|||
formEl.target = "_blank"; |
|||
formEl.method = "post"; |
|||
formEl.action = "http://codepad.org"; |
|||
formEl.style.display = "inline"; |
|||
var inputValues = [ |
|||
{ name: "lang", value: buttonBarCodepadLanguages[l].padName }, |
|||
{ name: "code", value: ButtonBarGetText(preEl) }, |
|||
{ name: "run", value: "True" }, |
|||
{ name: "private", value: "True" } |
|||
]; |
|||
for(var i = 0; i < inputValues.length; ++i) |
|||
{ |
|||
var inputEl = document.createElement("input"); |
|||
inputEl.setAttribute("type", "hidden"); |
|||
inputEl.setAttribute("name", inputValues[i].name); |
|||
inputEl.setAttribute("value", inputValues[i].value); |
|||
formEl.appendChild(inputEl); |
|||
} |
|||
//add and style the submit button to look like the other items |
|||
var inputEl = document.createElement("input"); |
|||
inputEl.setAttribute("type", "submit"); |
|||
inputEl.setAttribute("name", "submit"); |
|||
inputEl.setAttribute("value", "Try on Codepad"); |
|||
inputEl.style.border = "none"; |
|||
inputEl.style.background = "transparent"; |
|||
inputEl.style.cursor = "pointer"; |
|||
inputEl.style.textDecoration = "underline"; |
|||
inputEl.style.display = "inline-block"; |
|||
inputEl.style.padding = 0; |
|||
formEl.appendChild(inputEl); |
|||
break; |
|||
} |
|||
} |
|||
return false; |
|||
}; |
|||
} |
|||
function ButtonBarCreateMouseOut(preEl) |
|||
{ |
|||
//mouseout handler |
|||
return function(e) { |
|||
//if we're moving to another element inside of the same <pre>, add a mouseout handler and return |
|||
if(!e) e = window.event; |
|||
var target = e.relatedTarget || e.toElement; |
|||
if(IsChild(preEl, target)) |
|||
{ |
{ |
||
AddHandler(target, "mouseout", ButtonBarCreateMouseOut); |
|||
ulEls[ulEls.length] = ulEls[ulEls.length - 1].parentNode.insertBefore(document.createElement("ul"), ulEls[ulEls.length - 1].nextSibling); |
|||
return false; |
|||
} |
} |
||
//we're moving away from the container <pre>, so we need to remove all menu lists |
|||
//style the lists |
|||
var ulEls = preEl.getElementsByTagName("ul"); |
|||
for(var c = 0; c < ulEls.length; ++c) |
|||
for(var u = 0; u < ulEls.length; ++u) |
|||
{ |
{ |
||
ulEls[ |
ulEls[u].parentNode.removeChild(ulEls[u]); |
||
ulEls[c].style.cssFloat = "left"; |
|||
ulEls[c].style.verticalAlign = "top"; |
|||
ulEls[c].style.width = (95 / idealColumns) + "%"; |
|||
} |
} |
||
return false; |
|||
}; |
|||
//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 |
function ButtonBarActivate() |
||
{ |
{ |
||
//check to see if we're looking at a task page |
//check to see if we're looking at a task page |
||
Line 182: | Line 296: | ||
} |
} |
||
//look for language examples |
|||
//check to make sure we have a table of contents |
|||
var |
var allPres = document.getElementsByTagName("pre"); |
||
for(var p = 0; p < allPres.length; ++p) |
|||
if(tocEl) |
|||
{ |
{ |
||
if(allPres[p].className && allPres[p].className.indexOf("highlighted_source") >= 0) |
|||
//remove the extra show/hide button from the Contents area |
|||
var tocTitleEl = document.getElementById("toctitle"); |
|||
if(tocTitleEl) |
|||
{ |
{ |
||
//set up the onmouseover, onmousleave events to show/hide the button bar |
|||
var spanEls = tocTitleEl.getElementsByTagName("span"); |
|||
AddHandler(allPres[p], "mouseover", ButtonBarCreateMouseOver(allPres[p])); |
|||
var foundToggle = false; |
|||
AddHandler(allPres[p], "mouseout", ButtonBarCreateMouseOut(allPres[p])); |
|||
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 <div> |
|||
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(); |
|||
} |
|||
} |
|||
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 <h2> |
|||
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 <div> 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"; |
|||
} |
|||
} |
|||
} |
} |
||
} |
} |
||
Line 391: | Line 310: | ||
//register the comparison script with the window's load event |
//register the comparison script with the window's load event |
||
AddHandler(window, "load", ButtonBarActivate); |
|||
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; |
|||
} |
Revision as of 01:06, 6 July 2010
/*========================================
This comparison script was written by
Tyrok1, and has been tested on IE 7,
IE 8, Fx 3.6.3, and Fe 5.0.380.
========================================*/
//define the relationship between the CSS classes and the language names
var buttonBarCodepadLanguages = [
{ cssClass: "c", padName: "C" },
{ cssClass: "cpp", padName: "C++" },
{ cssClass: "d", padName: "D" },
{ cssClass: "haskell", padName: "Haskell" },
{ cssClass: "lua", padName: "Lua" },
{ cssClass: "ocaml", padName: "OCaml" },
{ cssClass: "php", padName: "PHP" },
{ cssClass: "perl", padName: "Perl" },
{ cssClass: "python", padName: "Python" },
{ cssClass: "ruby", padName: "Ruby" },
{ cssClass: "scheme", padName: "Scheme" },
{ cssClass: "tcl", padName: "Tcl" }
];
function AddHandler(el, handlerType, func)
{
//add an event handler in a more cross-browser way
if(el.addEventListener)
{
el.addEventListener(handlerType, func, false);
}
else if(el.attachEvent)
{
el.attachEvent("on" + handlerType, func);
}
else
{
eval("el.on" + handlerType + " = func;");
}
}
function IsChild(parent, child)
{
//check to see if an element is a child of another element
while(child && child != parent)
{
child = child.parentNode;
}
return (child == parent);
}
function ButtonBarSelectAll(preEl)
{
//select all code within a given <pre> element
var range = null;
var menuEl = preEl.getElementsByTagName("ul")[0];
if(((document.createRange && (range = document.createRange())) || (document.selection.createRange && (range = document.selection.createRange()))) && range.selectNodeContents)
{
//for Fx, Fe, and other more standards-compliant browsers
range.selectNodeContents(preEl);
range.setEndBefore(menuEl);
var sel = window.getSelection();
if(sel.setBaseAndExtent)
{
//odd variant of a few of the WebKit browsers
sel.setBaseAndExtent(preEl, 0, menuEl, 0);
}
else
{
sel.removeAllRanges();
sel.addRange(range);
}
}
else
{
//for IE
range = document.body.createTextRange();
range.moveToElementText(preEl);
var menuRange = document.body.createTextRange();
menuRange.moveToElementText(menuEl);
//deselect the popup menu
while(range.compareEndPoints("EndToStart", menuRange) > 0)
{
range.moveEnd("word", -1);
}
range.select();
}
//return the range so other functions can use it
return range;
}
function ButtonBarCreateSelectAll(preEl)
{
return function() {
//select all of the text in the pre element
ButtonBarSelectAll(preEl);
};
}
function ButtonBarCreateCopy(preEl)
{
return function() {
//copy all of the text in the pre element
//IE-only at this point
var range = ButtonBarSelectAll(preEl);
range.execCommand("Copy");
};
}
function ButtonBarGetText(preEl)
{
//get the code from inside of a <pre> element
var outText = "";
for(var c = 0; c < preEl.childNodes.length; ++c)
{
switch(preEl.childNodes[c].tagName ? preEl.childNodes[c].tagName.toLowerCase() : "")
{
case "br":
{
outText += "\n";
} break;
case "ul":
{
//get rid of s
outText = outText.replace(/\xA0/g, " ");
//return the cleaned text
return outText;
} break;
default:
{
outText += (preEl.childNodes[c].textContent ? preEl.childNodes[c].textContent : (preEl.childNodes[c].innerText ? preEl.childNodes[c].innerText : preEl.childNodes[c].data));
}
}
}
//get rid of s
outText = outText.replace(/\xA0/g, " ");
//return the cleaned text
return outText;
}
function ButtonBarAddSpacer(ulEl)
{
//add a spacer bullet item to the menu list
var spacerEl = ulEl.appendChild(document.createElement("li"));
spacerEl.appendChild(document.createTextNode("\u2022"));
spacerEl.style.display = "inline";
spacerEl.style.marginLeft = "0.5em";
spacerEl.style.marginRight = "0.5em";
}
function ButtonBarCreateMouseOver(preEl)
{
//the mouseover event handler for <pre> elements
return function() {
//if there's already a menu, don't add another
if(preEl.getElementsByTagName("ul").length > 0)
{
return false;
}
//style the <pre> and add the menu
preEl.style.position = "relative";
var ulEl = preEl.appendChild(document.createElement("ul"));
ulEl.className = "ButtonBar";
ulEl.style.position = "absolute";
ulEl.style.right = 0;
ulEl.style.top = 0;
ulEl.style.whitespace = "nowrap";
ulEl.style.marginRight = "0.5em";
//define actions we want to add
var listItems = [
{title:"Select All",code:ButtonBarCreateSelectAll(preEl)}
];
if(window.clipboardData)
{
listItems[listItems.length] = {title:"Copy to Clipboard",code:ButtonBarCreateCopy(preEl)};
}
//add the standard menu items
for(var i = 0; i < listItems.length; ++i)
{
//if it's not the first one, add a spacer
if(i > 0)
{
ButtonBarAddSpacer(ulEl);
}
var liEl = ulEl.appendChild(document.createElement("li"));
liEl.appendChild(document.createTextNode(listItems[i].title));
liEl.style.cursor = "pointer";
liEl.style.display = "inline";
liEl.style.fontFamily = "sans-serif";
liEl.style.textDecoration = "underline";
AddHandler(liEl, "click", listItems[i].code);
}
//check for a codepad-supported language
var langClass = preEl.className.split(" ")[0];
for(var l = 0; l < buttonBarCodepadLanguages.length; ++l)
{
if(langClass == buttonBarCodepadLanguages[l].cssClass)
{
//found the language
//add <li>s
ButtonBarAddSpacer(ulEl);
var liEl = ulEl.appendChild(document.createElement("li"));
liEl.style.display = "inline";
//build a form to submit to codepad
var formEl = liEl.appendChild(document.createElement("form"));
formEl.target = "_blank";
formEl.method = "post";
formEl.action = "http://codepad.org";
formEl.style.display = "inline";
var inputValues = [
{ name: "lang", value: buttonBarCodepadLanguages[l].padName },
{ name: "code", value: ButtonBarGetText(preEl) },
{ name: "run", value: "True" },
{ name: "private", value: "True" }
];
for(var i = 0; i < inputValues.length; ++i)
{
var inputEl = document.createElement("input");
inputEl.setAttribute("type", "hidden");
inputEl.setAttribute("name", inputValues[i].name);
inputEl.setAttribute("value", inputValues[i].value);
formEl.appendChild(inputEl);
}
//add and style the submit button to look like the other items
var inputEl = document.createElement("input");
inputEl.setAttribute("type", "submit");
inputEl.setAttribute("name", "submit");
inputEl.setAttribute("value", "Try on Codepad");
inputEl.style.border = "none";
inputEl.style.background = "transparent";
inputEl.style.cursor = "pointer";
inputEl.style.textDecoration = "underline";
inputEl.style.display = "inline-block";
inputEl.style.padding = 0;
formEl.appendChild(inputEl);
break;
}
}
return false;
};
}
function ButtonBarCreateMouseOut(preEl)
{
//mouseout handler
return function(e) {
//if we're moving to another element inside of the same <pre>, add a mouseout handler and return
if(!e) e = window.event;
var target = e.relatedTarget || e.toElement;
if(IsChild(preEl, target))
{
AddHandler(target, "mouseout", ButtonBarCreateMouseOut);
return false;
}
//we're moving away from the container <pre>, so we need to remove all menu lists
var ulEls = preEl.getElementsByTagName("ul");
for(var u = 0; u < ulEls.length; ++u)
{
ulEls[u].parentNode.removeChild(ulEls[u]);
}
return false;
};
}
function ButtonBarActivate()
{
//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;
}
//look for language examples
var allPres = document.getElementsByTagName("pre");
for(var p = 0; p < allPres.length; ++p)
{
if(allPres[p].className && allPres[p].className.indexOf("highlighted_source") >= 0)
{
//set up the onmouseover, onmousleave events to show/hide the button bar
AddHandler(allPres[p], "mouseover", ButtonBarCreateMouseOver(allPres[p]));
AddHandler(allPres[p], "mouseout", ButtonBarCreateMouseOut(allPres[p]));
}
}
}
//register the comparison script with the window's load event
AddHandler(window, "load", ButtonBarActivate);