User:Atelaes/TabbedLanguages.js
Note – after saving, you may have to bypass your browser’s cache to see the changes.
- Mozilla / Firefox / Safari: hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (Command-R on a Macintosh);
- Konqueror and Chrome: click Reload or press F5;
- Opera: clear the cache in Tools → Preferences;
- Internet Explorer: hold Ctrl while clicking Refresh, or press Ctrl-F5.
- This script lacks a documentation subpage. Please create it.
- Useful links: root page • root page’s subpages • links • redirects • your own
var tabbedLanguages = [];
var tabLangSectionNums = {};
var tabLangTOC = {};
/*
* Modelled after function described at http://robertnyman.com/2005/11/07/the-ultimate-getelementsbyclassname/
*/
if (document.getElementsByClassName == undefined) {
function homeBrewElementsByClassName(className) {
var child;
var results = [];
var allChildren = this.getElementsByTagName('*');
for (var a=0; a<allChildren.length; a++) {
child = allChildren[a];
childClass = child.className;
regexTest = new RegExp('(^|\\s)' + className + '(\\s|$)');
if (regexTest.test(childClass)) {
results.push(child);
}
}
return results;
}
Document.prototype.getElementsByClassName = homeBrewElementsByClassName;
Element.prototype.getElementsByClassName = homeBrewElementsByClassName;
}
/*
*Taken from https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Array/indexOf
*/
if (!Array.prototype.indexOf)
{
Array.prototype.indexOf = function(elt /*, from*/)
{
var len = this.length >>> 0;
var from = Number(arguments[1]) || 0;
from = (from < 0)
? Math.ceil(from)
: Math.floor(from);
if (from < 0)
from += len;
for (; from < len; from++)
{
if (from in this &&
this[from] === elt)
return from;
}
return -1;
};
}
function makeLanguageTabs()
{
if (wgNamespaceNumber == 0) {
// Start by looking at all the L2 headers, which, in the main namespace, should all be languages.
// Generate containers, placed immediately before the headers,
// and create a list of all the languages the page contains.
// Also, remember the section numbers of the edit links, so we can recreate them after they're nuked.
var languageContainer, languageContainers, li, languageLinks, toc;
var EditSectionNumber = false;
var language = false;
var headerLanguageSection = false;
var tabbedTOCPrefs = 'sectioned'; //Gotta find a way to institute a pref about that.
var bodyContent = document.getElementById('bodyContent');
for (var child = bodyContent.firstChild; child != null; child = child.nextSibling) {
if (child.nodeName.toUpperCase() == 'H2') {
EditSectionNumber = false;
language = false;
headerLanguageSection = false;
var spans = child.getElementsByTagName('span');
if (spans[1] && spans[1].className == 'mw-headline') {
headerLanguageSection = spans[1];
EditSectionNumber = spans[0].getElementsByTagName('a')[0].href.split('section=')[1];
}
else if (spans[0] && spans[0].className == 'mw-headline') {
headerLanguageSection = spans[0];
}
if (headerLanguageSection) {
if (headerLanguageSection.getElementsByTagName('a').length > 0) {
language = headerLanguageSection.getElementsByTagName('a')[0].innerHTML;
headerLanguageSection.innerHTML = '';
}
else {
language = headerLanguageSection.innerHTML;
headerLanguageSection.innerHTML = '';
}
}
if (language) {
tabbedLanguages.push(language);
languageContainer = newNode('div', {'class' : 'languageContainer', 'id' : language + 'container'});
bodyContent.insertBefore(languageContainer, child);
if (EditSectionNumber) {
tabLangSectionNums[language] = EditSectionNumber;
}
}
}
if (document.getElementById('toc')) {
toc = document.getElementById('toc');
tocLangSections = toc.getElementsByClassName('toclevel-1');
for (var c = 0; c < tocLangSections.length; c++) {
if (tocLangSections[c].className.split('tocsection-')[1] == tabLangSectionNums[language]) {
tabLangTOC[language] = tocLangSections[c];
tocLangSections[c].parentNode.removeChild(tocLangSections[c]);
}
}
}
}
if (document.getElementById('toc')) {
var throwAway = VisibilityToggles.register('TOC',
function show() {
addCSSRule('#toc', 'display:table');
},
function hide() {
addCSSRule('#toc', 'display:none');
});
}
// Make the toggle.
languageLinks = newNode('div', {'id' : 'languageLinks'});
for (var b = 0; b < tabbedLanguages.length; b++) {
language = tabbedLanguages[b];
languageLink = newNode('a', language, {'href' : '#' + language});
languageLinks.appendChild(newNode('span', languageLink, {'class' : 'unselectedTab'}));
languageLinks.appendChild(newNode('wbr'));
}
// If there are section edit links, reproduce them, within a non-float container to make room.
if (EditSectionNumber) {
var LLEditSection = newNode('span', '[', newNode('a', 'edit', {'href' : 'emptyURL'}), ']', {'class' : 'editsection'});
languageLinks.appendChild(newNode('span', LLEditSection, {'class' : 'LLeditContainer'}));
}
//Make the toggle so pretty that you want to walk over and buy it a drink.
if (skin == 'vector') {
addCSSRule('#languageLinks .unselectedTab', 'height:2.5em; padding:1.25em 0 .5em;\
background-image:url("http://bits.wikimedia.org/skins-1.5/vector/images/tab-normal-fade.png?1"); \
background-position:left bottom; background-repeat:repeat-x;');
addCSSRule('#languageLinks .selectedTab', 'height:2.5em; padding:1.25em 0 .5em;');
addCSSRule('#languageLinks .selectedTab a', 'cursor:pointer; color:#333333; height:2.5em; padding-left:0.4em; \
padding-right:0.4em; line-height:3.1em; white-space:nowrap; padding-top:1.25em; padding-bottom:.5em; \
background-image:url("http://bits.wikimedia.org/skins-1.5/vector/images/tab-break.png?1"); \
background-position:right bottom; background-repeat:no-repeat;');
addCSSRule('#languageLinks .unselectedTab a', 'cursor:pointer; color:#0645AD; height:2.5em; padding-left:0.4em; \
padding-right:0.4em; line-height:3.1em; white-space:nowrap; padding-top:1.25em; padding-bottom:.5em; \
background-image:url("http://bits.wikimedia.org/skins-1.5/vector/images/tab-break.png?1"); \
background-position:right bottom; background-repeat:no-repeat;');
addCSSRule('.LLEditContainer', 'width : 3em;');
}
else {
addCSSRule('#languageLinks .unselectedTab', 'line-height : 1.5em; display : inline; padding : 0 0.5em; \
border : 1px solid #AAAAAA; background : #E8E8E8; white-space:nowrap;');
addCSSRule('#languageLinks .selectedTab', 'line-height : 1.5em; display : inline; padding : 0 0.5em; \
border : 1px solid #AAAAAA; border-bottom : none; background : white; white-space:nowrap');
addCSSRule('#languageLinks a', 'color : #0645AD');
}
// Finally, stuff all the content into the appropriate language container.
languageContainers = document.getElementsByClassName('languageContainer');
var neighbor;
for (var a = 0; a < languageContainers.length; a++) {
languageContainer = languageContainers[a];
if (a == 0) {
bodyContent.insertBefore(languageLinks, languageContainer);
}
else {
languageContainer.style.display = 'none';
}
while (true) {
neighbor = languageContainer.nextSibling;
if (!neighbor) {
break;
}
else if (neighbor.className == 'languageContainer') {
break;
}
else if (neighbor.className == 'printfooter' || neighbor.className == 'catlinks') {
break;
}
else if (neighbor.nodeName.toUpperCase() == 'HR') {
neighbor.parentNode.removeChild(neighbor);
}
else if (neighbor.nodeName.toUpperCase() == 'H2') {
neighbor.parentNode.removeChild(neighbor);
}
else {
languageContainer.appendChild(neighbor);
}
}
// Put a container in each for categories. These will be populated later.
languageContainer.appendChild(newNode('div', newNode('text', languageContainer.id.split('container')[0] + ' categories: '), {'class' : 'catlinks'}));
}
// Now for category sorting, courtesy of Yair rand.
var catDiv = document.getElementById('catlinks');
var cats, catname;
var catSections = catDiv.getElementsByTagName('div');
for (var d=0; d<catSections.length; d++) {
cats = catSections[d].getElementsByTagName('span');
var langcurrent=0;
while (cats.length > 0) {
z=0;
catname = cats[z].getElementsByTagName('a')[0].innerHTML;
while(catname.match(/derivations/)) {
z+=1;
catname = cats[z].getElementsByTagName('a')[0].innerHTML;
}
if(catname.match(new RegExp("^"+tabbedLanguages[langcurrent+1]))&&!catname.match(/letter\snames$/)&&!catname.match(/script\scharacters$/))
{langcurrent+=1}
var currentCatDiv = languageContainers[langcurrent].getElementsByClassName('catlinks')[0]
if (currentCatDiv.lastChild.nodeName.toUpperCase() == 'SPAN') {
currentCatDiv.appendChild(newNode('text', ' | '))
}
languageContainers[langcurrent].getElementsByClassName('catlinks')[0].appendChild(cats[0]);
}
}
catDiv.parentNode.removeChild(catDiv);
// If there's a location hash, the window may have scrolled down before we got a chance to reorganize everything.
// If the destination was a sense id, switch to the right tab, and rescroll.
// If it was simply a language, switch to the appropriate tab, and scroll back up.
// If it was anything else (e.g. #Noun, #Etymology 1) , switch to the first tab, and try scrolling to it.
// Note that the above method is not reliable, as the link author may have intended the "noun" of a different language.
// However, it's unreliable anyway, even if tabbed languages does make it less reliable.
if (window.location.hash != '') {
var hash = decodeURI(window.location.hash).substr(1);
if (hash.indexOf('-') > -1) {
var destination = hash.split('-')[0].replace('_', ' ');
toggleLanguageTabs(destination);
window.location.hash = window.location.hash;
}
else if (tabbedLanguages.indexOf(hash.replace('_', ' ')) > -1) {
var destination = hash.replace('_', ' ');
toggleLanguageTabs(destination);
if (window.scrollY) {
window.scroll(0,0);
}
}
else {
toggleLanguageTabs(tabbedLanguages[0]);
window.location.hash = window.location.hash;
}
}
else {
toggleLanguageTabs(tabbedLanguages[0]);
}
window.onhashchange = hashToggleLT;
}
}
function hashToggleLT ()
{
var destination = decodeURI(window.location.hash.substr(1)).replace('_', ' ');
toggleLanguageTabs(destination);
}
function toggleLanguageTabs(language)
{
if (tabbedLanguages.indexOf(language) != -1) {
var languageButtons = document.getElementById('languageLinks').getElementsByTagName('span');
for (var b = 0; b < languageButtons.length; b++) {
if (languageButtons[b].firstChild.innerHTML == language) {
languageButtons[b].className = 'selectedTab';
}
else if (languageButtons[b].className == 'selectedTab') {
languageButtons[b].className = 'unselectedTab';
}
}
var languageContainers = document.getElementsByClassName('languageContainer');
for (var a = 0; a < languageContainers.length; a++) {
if (languageContainers[a].id.indexOf(language) != 0) {
languageContainers[a].style.display = 'none';
}
else {
languageContainers[a].style.display = 'block';
}
}
if (document.getElementById('languageLinks').getElementsByClassName('editsection')[0] != undefined) {
var editSection = document.getElementById('languageLinks').getElementsByClassName('editsection')[0];
var editSectionHref = '/w/index.php?title=' + wgPageName + '&action=edit§ion=' + tabLangSectionNums[language];
editSection.getElementsByTagName('a')[0].href = editSectionHref;
}
if (document.getElementById('toc')) {
var emptyTOC = document.getElementById('toc').getElementsByTagName('ul')[0];
emptyTOC.innerHTML = '';
emptyTOC.appendChild(tabLangTOC[language].cloneNode(true));
}
}
}
$( makeLanguageTabs );