User:MikeMol/monobook.js: Difference between revisions

From Rosetta Code
Content added Content deleted
(Try the buton bar)
(Try the coloring code)
Line 1: Line 1:
//<lang javascript>
/*========================================
/*========================================
This comparison script was written by
This menu script was written by
Tyrok1, and has been tested on IE 5.5,
Tyrok1, and has been tested on Fx 3.6.6,
Cr 5.0.375.99, Epiphany 2.30.2,
IE 6, IE 7, IE 8, Fx 3.6.2, and
Fe 4.0.280.
Midori 0.2.2
========================================*/
========================================*/
function GetElWidth(el)
{
return (el.clientWidth ? el.clientWidth : el.offsetWidth);
}


var gadgetsAvailable = [
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 <ul> 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.floor(GetElWidth(tocEl) / maxWidth);
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)
{
{
id: "LanguageComparison",
spanEls[s].parentNode.removeChild(spanEls[s]);
name: "Language comparison",
}
url: "http://rosettacode.org/mw/index.php" +
foundToggle = true;
"?title=Rosetta_Code:Language_comparison_script" +
}
"&action=raw&ctype=text/javascript",
}
prefix: "Compare"
}
},
//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)
{
{
id: "Highlight",
var oldWidth = GetElWidth(preEls[p]);
name: "Syntax Highlight Color Picker",
preEls[p].style.cssFloat = "left";
url: "http://rosettacode.org/mw/index.php" +
if(GetElWidth(preEls[p]) == oldWidth)
"?title=Rosetta_Code:Syntax_Highlight_Color_Picker" +
{
"&action=raw&ctype=text/javascript",
//assume it's either wider than the window or IE where they don't shrink
prefix: "Highlight"
//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)
{
{
id: "UtilityButtonBar",
var h2Els = aEls[a].parentNode.getElementsByTagName("h2");
name: "Utility button bar",
if(h2Els.length > 0)
url: "http://rosettacode.org/mw/index.php" +
{
"?title=Rosetta_Code:Per-Code_Example_Buttonbar" +
//we have at least one h2
"&action=raw&ctype=text/javascript",
//use its width
prefix: "ButtonBar"
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";
}
}
}
}
}


function GadgetsAddHandler(el, handlerType, func)
//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;
}

/*========================================
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
//add an event handler in a more cross-browser way
Line 447: Line 50:
}
}
}
}

function IsChild(parent, child)
function GadgetsScriptLoad(g)
{
{
//check to see if an element is a child of another element
//see if we need to load it
//if we don't, there's not much point in loading it again
while(child && child != parent)
if(!document.getElementById("GadgetScript" + g))
{
{
var scriptEl = document.createElement("script");
child = child.parentNode;
scriptEl.setAttribute("id", "GadgetScript" + g);
scriptEl.setAttribute("type", "text/javascript");
scriptEl.setAttribute("src", gadgetsAvailable[g].url);
document.documentElement.appendChild(scriptEl);
}
}
return (child == parent);
}
}

function ButtonBarSelectAll(preEl)
function GadgetsScriptActivate(g)
{
{
//check to see if the script's finished loading
//select all code within a given <pre> element
if(eval("typeof " + gadgetsAvailable[g].prefix + "Activate") == "undefined")
var range = null;
var menuEl = preEl.getElementsByTagName("ul")[0];
if(((document.createRange && (range = document.createRange())) || (document.selection.createRange && (range = document.selection.createRange()))) && range.selectNodeContents)
{
{
//not finished yet - try reactivating in another 0.5s
//for Fx, Fe, and other more standards-compliant browsers
setTimeout(function() { GadgetsScriptActivate(g); }, 500);
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
else
{
{
//run the activation function
//for IE
eval(gadgetsAvailable[g].prefix + "Activate();");
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)
function GadgetsScriptDeactivate(g)
{
{
//check to see if the specified script has a deactivation function
return function() {
if(eval("typeof " + gadgetsAvailable[g].prefix + "Deactivate") != "undefined")
//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)
{
{
//it does - run it
switch(preEl.childNodes[c].tagName ? preEl.childNodes[c].tagName.toLowerCase() : "")
eval(gadgetsAvailable[g].prefix + "Deactivate();");
{
}
case "br":
else
{
{
outText += "\n";
//pop up a warning to the user to let them know
} break;
//the plugin will be disabled when they reload
case "ul":
alert("This script will be disabled on next page load");
{
//get rid of &nbsp;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 &nbsp;s
outText = outText.replace(/\xA0/g, " ");
//return the cleaned text
return outText;
}
}

function ButtonBarAddSpacer(ulEl)
function GadgetsCreateCheckboxClosure(el)
{
{
//add a spacer bullet item to the menu list
//create an onclick handler for the script checkboxes
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() {
return function() {
//if there's already a menu, don't add another
//save the checkboxes to the cookie for next page load
GadgetsSaveCheckboxes();
if(preEl.getElementsByTagName("ul").length > 0)
//check to see if we need to activate or deactivate
if(el.checked)
{
{
//load and activate the script
return false;
GadgetsScriptLoad(el.value);
GadgetsScriptActivate(el.value);
}
}
else
//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)
{
{
//deactivate the script
listItems[listItems.length] = {title:"Copy to Clipboard",code:ButtonBarCreateCopy(preEl)};
GadgetsScriptDeactivate(el.value);
}
}
//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)
function GadgetsMouseOver()
{
{
//show the scripts dropdown
//mouseout handler
document.getElementById("pt-jsgadgets-list").style.display = "block";
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;
function GadgetsMouseOut()
var target = e.relatedTarget || e.toElement;
{
if(IsChild(preEl, target))
//hide the scripts dropdown
document.getElementById("pt-jsgadgets-list").style.display = "none";
}

function GadgetsSaveCheckboxes()
{
var checkedBoxes = "", checkboxEl = null;
//build a string representation of all of the checked boxes to save to the cookie
for(var c = 0; checkboxEl = document.getElementById("pt-jsgadgets-gadget" + c); ++c)
{
if(checkboxEl.checked)
{
if(checkedBoxes != "")
{
{
checkedBoxes += ",";
AddHandler(target, "mouseout", ButtonBarCreateMouseOut);
return false;
}
}
checkedBoxes += gadgetsAvailable[c].id;
}
//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)
//set an expiry date 1000 years into the future
{
var expireDate = new Date();
ulEls[u].parentNode.removeChild(ulEls[u]);
expireDate.setFullYear(expireDate.getFullYear() + 1000);
}
return false;
//store the cookie
};
document.cookie = "jsGadgets=" + escape(checkedBoxes) +
"; expires=" + expireDate.toUTCString();
}
}

function ButtonBarActivate()
function GadgetsGetCheckboxes()
{
{
//check to see if we're looking at a task page
//pull in the cookie and look for the jsGadgets key
var catLinksEl = document.getElementById("catlinks");
var fullCookie = document.cookie;
var gadgetsPos = fullCookie.indexOf("jsGadgets=");
var isTask = false;
if(catLinksEl)
if(gadgetsPos < 0)
{
//no gadgets in the cookie
return new Array();
}
var endPos = fullCookie.indexOf(";", gadgetsPos);
//split the gadget IDs by comma
var jsGadgets = fullCookie.substring(gadgetsPos + ("jsGadgets=").length,
(endPos > 0 ? endPos : fullCookie.length));
var checkIDs = unescape(jsGadgets).split(",");
//translate the list of IDs to a list of array indices,
//in keeping with the way the rest of this module works
var checkIndices = new Array();
for(var g = 0; g < gadgetsAvailable.length; ++g)
{
{
for(var c = 0; c < checkIDs.length; ++c)
var aEls = catLinksEl.getElementsByTagName("a");
for(var a = 0; a < aEls.length; ++a)
{
{
if(gadgetsAvailable[g].id == checkIDs[c])
if(aEls[a].getAttribute("title") == "Category:Programming Tasks")
{
{
checkIndices[checkIndices.length] = g;
//it's a task
isTask = true;
break;
break;
}
}
}
}
}
}
return checkIndices;
if(!isTask)
}

function GadgetsActivate()
{
//find the user preferences button and add a new list item to the right of it
var prefsEl = document.getElementById("pt-preferences");
if(!prefsEl)
{
{
var personalEl = document.getElementById("p-personal");
return;
if(!personalEl)
}
//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)
{
{
return;
//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]));
}
}
var liEls = personalEl.getElementsByTagName("li");
if(!liEls || liEls.length < 2)
{
return;
}
prefsEl = liEls[liEls.length - 2];
}
var jsMenuEl = prefsEl.parentNode.insertBefore(
document.createElement("li"), prefsEl.nextSibling);
jsMenuEl.setAttribute("id", "pt-jsgadgets");
//add a new link named "My scripts" in the new list item
//from a semantics point of view, this is not great,
//but this way the styling kicks in to keep it consistent with its siblings
var jsLinkEl = jsMenuEl.appendChild(document.createElement("a"));
jsLinkEl.appendChild(document.createTextNode("My scripts"));
jsLinkEl.setAttribute("href", "javascript: void(0);");
jsLinkEl.style.position = "relative";
//add handlers for showing on mouseover and hiding on mouseout
GadgetsAddHandler(jsLinkEl, "mouseover", GadgetsMouseOver);
GadgetsAddHandler(jsLinkEl, "mouseout", GadgetsMouseOut);
//build a list for showing available JS gadgets
var modulesListEl = jsLinkEl.appendChild(document.createElement("ol"));
modulesListEl.setAttribute("id", "pt-jsgadgets-list");
modulesListEl.style.listStyle = "none";
modulesListEl.style.margin = 0;
modulesListEl.style.padding = 0;
modulesListEl.style.position = "absolute";
modulesListEl.style.top = "100%";
modulesListEl.style.left = 0;
modulesListEl.style.backgroundColor = "#fff";
modulesListEl.style.border = "1px solid #69c";
modulesListEl.style.padding = "0.5em";
modulesListEl.style.display = "none";
//raise the zIndex of the new button (as well as
//a few parents) so the menu overlaps the page
var zEl = modulesListEl;
for(var z = 0; z < 6 && zEl && zEl.style; ++z, zEl = zEl.parentNode)
{
zEl.style.zIndex = 100;
}
//add each of the gadgets to the list
for(var m = 0; m < gadgetsAvailable.length; ++m)
{
//add the list item element
var liEl = modulesListEl.appendChild(document.createElement("li"));
liEl.style.display = "block";
liEl.style.cssFloat = "none";
liEl.style.right = "auto";
liEl.style.left = 0;
liEl.style.textAlign = "left";
liEl.style.margin = 0;
liEl.style.padding = 0;
//add the checkbox
var inputEl = document.createElement("input");
var checkboxId = "pt-jsgadgets-gadget" + m;
inputEl.setAttribute("type", "checkbox");
inputEl.setAttribute("id", checkboxId);
inputEl.setAttribute("value", m);
GadgetsAddHandler(inputEl, "click", GadgetsCreateCheckboxClosure(inputEl));
liEl.appendChild(inputEl);
//add the label
var labelEl = document.createElement("label");
labelEl.setAttribute("for", checkboxId);
labelEl.appendChild(document.createTextNode(gadgetsAvailable[m].name));
labelEl.style.paddingLeft = "1em";
liEl.appendChild(labelEl);
}
//fetch the saved checkboxes from the cookie
var checks = GadgetsGetCheckboxes();
for(var c = 0; c < checks.length; ++c)
{
//for each one that should be checked on page load,
//check the box, load, and activate it
document.getElementById("pt-jsgadgets-gadget" + checks[c]).checked = true;
GadgetsScriptLoad(checks[c]);
GadgetsScriptActivate(checks[c]);
}
}
}
}

//register the comparison script with the window's load event
//register the comparison script with the window's load event
AddHandler(window, "load", ButtonBarActivate);
GadgetsAddHandler(window, "load", GadgetsActivate);
//</lang>

Revision as of 01:28, 7 July 2011

//<lang javascript>
/*========================================
This menu script was written by
Tyrok1, and has been tested on Fx 3.6.6,
Cr 5.0.375.99, Epiphany 2.30.2,
Midori 0.2.2
========================================*/

var gadgetsAvailable = [
					{
						id: "LanguageComparison",
						name: "Language comparison",
						url: "http://rosettacode.org/mw/index.php" +
							"?title=Rosetta_Code:Language_comparison_script" + 
							"&action=raw&ctype=text/javascript",
						prefix: "Compare"
					},
					{
						id: "Highlight",
						name: "Syntax Highlight Color Picker",
						url: "http://rosettacode.org/mw/index.php" +
							"?title=Rosetta_Code:Syntax_Highlight_Color_Picker" +
							"&action=raw&ctype=text/javascript",
						prefix: "Highlight"
					},
					{
						id: "UtilityButtonBar",
						name: "Utility button bar",
						url: "http://rosettacode.org/mw/index.php" +
							"?title=Rosetta_Code:Per-Code_Example_Buttonbar" +
							"&action=raw&ctype=text/javascript",
						prefix: "ButtonBar"
					}
				];

function GadgetsAddHandler(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 GadgetsScriptLoad(g)
{
	//see if we need to load it
	//if we don't, there's not much point in loading it again
	if(!document.getElementById("GadgetScript" + g))
	{
		var scriptEl = document.createElement("script");
		scriptEl.setAttribute("id", "GadgetScript" + g);
		scriptEl.setAttribute("type", "text/javascript");
		scriptEl.setAttribute("src", gadgetsAvailable[g].url);
		document.documentElement.appendChild(scriptEl);
	}
}

function GadgetsScriptActivate(g)
{
	//check to see if the script's finished loading
	if(eval("typeof " + gadgetsAvailable[g].prefix + "Activate") == "undefined")
	{
		//not finished yet - try reactivating in another 0.5s
		setTimeout(function() { GadgetsScriptActivate(g); }, 500);
	}
	else
	{
		//run the activation function
		eval(gadgetsAvailable[g].prefix + "Activate();");
	}
}

function GadgetsScriptDeactivate(g)
{
	//check to see if the specified script has a deactivation function
	if(eval("typeof " + gadgetsAvailable[g].prefix + "Deactivate") != "undefined")
	{
		//it does - run it
		eval(gadgetsAvailable[g].prefix + "Deactivate();");
	}
	else
	{
		//pop up a warning to the user to let them know
		//the plugin will be disabled when they reload
		alert("This script will be disabled on next page load");
	}
}

function GadgetsCreateCheckboxClosure(el)
{
	//create an onclick handler for the script checkboxes
	return function() {
				//save the checkboxes to the cookie for next page load
				GadgetsSaveCheckboxes();
				
				//check to see if we need to activate or deactivate
				if(el.checked)
				{
					//load and activate the script
					GadgetsScriptLoad(el.value);
					GadgetsScriptActivate(el.value);
				}
				else
				{
					//deactivate the script
					GadgetsScriptDeactivate(el.value);
				}
			};
}

function GadgetsMouseOver()
{
	//show the scripts dropdown
	document.getElementById("pt-jsgadgets-list").style.display = "block";
}

function GadgetsMouseOut()
{
	//hide the scripts dropdown
	document.getElementById("pt-jsgadgets-list").style.display = "none";
}

function GadgetsSaveCheckboxes()
{
	var checkedBoxes = "", checkboxEl = null;
	
	//build a string representation of all of the checked boxes to save to the cookie
	for(var c = 0; checkboxEl = document.getElementById("pt-jsgadgets-gadget" + c); ++c)
	{
		if(checkboxEl.checked)
		{
			if(checkedBoxes != "")
			{
				checkedBoxes += ",";
			}
			checkedBoxes += gadgetsAvailable[c].id;
		}
	}
	
	//set an expiry date 1000 years into the future
	var expireDate = new Date();
	expireDate.setFullYear(expireDate.getFullYear() + 1000);
	
	//store the cookie
	document.cookie = "jsGadgets=" + escape(checkedBoxes) +
			"; expires=" + expireDate.toUTCString();
}

function GadgetsGetCheckboxes()
{
	//pull in the cookie and look for the jsGadgets key
	var fullCookie = document.cookie;
	var gadgetsPos = fullCookie.indexOf("jsGadgets=");
	if(gadgetsPos < 0)
	{
		//no gadgets in the cookie
		return new Array();
	}
	var endPos = fullCookie.indexOf(";", gadgetsPos);
	
	//split the gadget IDs by comma
	var jsGadgets = fullCookie.substring(gadgetsPos + ("jsGadgets=").length,
					(endPos > 0 ? endPos : fullCookie.length));
	var checkIDs = unescape(jsGadgets).split(",");
	
	//translate the list of IDs to a list of array indices,
	//in keeping with the way the rest of this module works
	var checkIndices = new Array();
	for(var g = 0; g < gadgetsAvailable.length; ++g)
	{
		for(var c = 0; c < checkIDs.length; ++c)
		{
			if(gadgetsAvailable[g].id == checkIDs[c])
			{
				checkIndices[checkIndices.length] = g;
				break;
			}
		}
	}
	return checkIndices;
}

function GadgetsActivate()
{
	//find the user preferences button and add a new list item to the right of it
	var prefsEl = document.getElementById("pt-preferences");
	if(!prefsEl)
	{
		var personalEl = document.getElementById("p-personal");
		if(!personalEl)
		{
			return;
		}
		var liEls = personalEl.getElementsByTagName("li");
		if(!liEls || liEls.length < 2)
		{
			return;
		}
		prefsEl = liEls[liEls.length - 2];
	}
	var jsMenuEl = prefsEl.parentNode.insertBefore(
				document.createElement("li"), prefsEl.nextSibling);
	jsMenuEl.setAttribute("id", "pt-jsgadgets");
	
	//add a new link named "My scripts" in the new list item
	//from a semantics point of view, this is not great,
	//but this way the styling kicks in to keep it consistent with its siblings
	var jsLinkEl = jsMenuEl.appendChild(document.createElement("a"));
	jsLinkEl.appendChild(document.createTextNode("My scripts"));
	jsLinkEl.setAttribute("href", "javascript: void(0);");
	jsLinkEl.style.position = "relative";
	
	//add handlers for showing on mouseover and hiding on mouseout
	GadgetsAddHandler(jsLinkEl, "mouseover", GadgetsMouseOver);
	GadgetsAddHandler(jsLinkEl, "mouseout", GadgetsMouseOut);
	
	//build a list for showing available JS gadgets
	var modulesListEl = jsLinkEl.appendChild(document.createElement("ol"));
	modulesListEl.setAttribute("id", "pt-jsgadgets-list");
	modulesListEl.style.listStyle = "none";
	modulesListEl.style.margin = 0;
	modulesListEl.style.padding = 0;
	modulesListEl.style.position = "absolute";
	modulesListEl.style.top = "100%";
	modulesListEl.style.left = 0;
	modulesListEl.style.backgroundColor = "#fff";
	modulesListEl.style.border = "1px solid #69c";
	modulesListEl.style.padding = "0.5em";
	modulesListEl.style.display = "none";
	
	//raise the zIndex of the new button (as well as
	//a few parents) so the menu overlaps the page
	var zEl = modulesListEl;
	for(var z = 0; z < 6 && zEl && zEl.style; ++z, zEl = zEl.parentNode)
	{
		zEl.style.zIndex = 100;
	}
	
	//add each of the gadgets to the list
	for(var m = 0; m < gadgetsAvailable.length; ++m)
	{
		//add the list item element
		var liEl = modulesListEl.appendChild(document.createElement("li"));
		liEl.style.display = "block";
		liEl.style.cssFloat = "none";
		liEl.style.right = "auto";
		liEl.style.left = 0;
		liEl.style.textAlign = "left";
		liEl.style.margin = 0;
		liEl.style.padding = 0;
		
		//add the checkbox
		var inputEl = document.createElement("input");
		var checkboxId = "pt-jsgadgets-gadget" + m;
		inputEl.setAttribute("type", "checkbox");
		inputEl.setAttribute("id", checkboxId);
		inputEl.setAttribute("value", m);
		GadgetsAddHandler(inputEl, "click", GadgetsCreateCheckboxClosure(inputEl));
		liEl.appendChild(inputEl);
		
		//add the label
		var labelEl = document.createElement("label");
		labelEl.setAttribute("for", checkboxId);
		labelEl.appendChild(document.createTextNode(gadgetsAvailable[m].name));
		labelEl.style.paddingLeft = "1em";
		liEl.appendChild(labelEl);
	}
	
	//fetch the saved checkboxes from the cookie
	var checks = GadgetsGetCheckboxes();
	for(var c = 0; c < checks.length; ++c)
	{
		//for each one that should be checked on page load,
		//check the box, load, and activate it
		document.getElementById("pt-jsgadgets-gadget" + checks[c]).checked = true;
		GadgetsScriptLoad(checks[c]);
		GadgetsScriptActivate(checks[c]);
	}
}

//register the comparison script with the window's load event
GadgetsAddHandler(window, "load", GadgetsActivate);
//</lang>