User:Yair rand/sandbox.js

(function ( $ ) { // This is a (very) modified version of User:Atelaes/TabbedLanguages.js. // Tabbed languages with tabs on the side. // Tabs design by User:Jorm (WMF) // Currently undergoing rewrite in order to eliminate delay.

// Remember to remove extra console.logs before deploying.

if (($.cookie('disable-tabbed-languages') !== null) || (location.search.indexOf("tabbedlanguages=off") !== -1)) return; if (!((mw.config.get('wgNamespaceNumber') === 0) || (mw.config.get('wgPageName') === "Wiktionary:Sandbox"))) return;

var bodyContent = $(".mw-content-ltr")[0], // NOT #bodyContent observerStyleSheet, languageLinks, ttr, languageButtons = [], isIE9 = $.client.profile.name === "msie" && $.client.profile.versionNumber == 9, caption, bodyContentFragment, complete = false;

// Setting up the tabs has not yet been started. function makeTabsfromScratch { // Set up the variables... window.tabbedLanguages = []; window.languageContainers = []; window.currentLanguageTab = 0; window.languageHeaderEditButtons = []; window.tabstable = newNode('table', {id: 'tabstable'}, 		newNode('tbody', ttr = newNode('tr', 				newNode('td', {'style': 'padding-top:0px;vertical-align:top;'}, newNode('table', {'style': 'margin-top: -2px;'}, 						languageLinks = newNode('tbody', {id: 'languageLinks'})))))); window.loadremovecatbuttons = false; bodyContentFragment = document.createDocumentFragment; // If bodyContent is complete, do it all at once. // Otherwise, only start working, but don't attempt the whole thing. // Use catlinks+*, as gEBCN isn't always available. var catlinks = document.getElementById( "catlinks" ); if( bodyContent && catlinks && catlinks.nextSibling ) { allAtOnce; } else { createObserver; } }

function allAtOnce { console.log( "allAtOnce"); var languageContainer, toc = document.getElementById( "toc" ); currentLanguageTab = 0; while ( bodyContent.firstChild ) { bodyContentFragment.appendChild( bodyContent.firstChild ); }	try { for( var child = bodyContentFragment.firstChild; child && !isHeader( child ); ){ child = child.nextSibling; }		for (			child = child && bodyContentFragment.insertBefore(tabstable, child).nextSibling; 			child && child.className !== 'printfooter' && child.className !== 'catlinks'; 			child = child.nextSibling		) { if ( isHeader( child ) ) { var spans = child.getElementsByTagName('span'), span = spans[ 0 ], language = span && ( span.innerText || span.textContent ); if ( language ) { newTab( tabbedLanguages.push(language) - 1, language ); processEditButton( spans[ 1 ] ); // should probably be set from a return value of above. languageContainer = languageContainers[ languageContainers.length - 1 ]; bodyContentFragment.removeChild( child ); child = tabstable; }			} else { if ( child.nodeName !== "HR" ) { languageContainer.insertBefore(child, languageContainer.lastChild); } else { bodyContentFragment.removeChild(child); }				child = tabstable; }		}		if( tabbedLanguages.length ) { if( toc ) { toc.parentNode.removeChild( toc ); }			sortCats; bodyContent.appendChild( bodyContentFragment ); setUpHashChange; if( location.hash === '' ) { console.log( "Replacing hash with current tab" ); location.replace( "#" + tabbedLanguages[ currentLanguageTab ] ); }			complete = true; } else { bodyContent.appendChild( bodyContentFragment ); }	} catch( e ) { window.console && console.log( e ); bodyContent.appendChild( bodyContentFragment ); complete || setUpHashChange; } }

// Set up a stylesheet that uses animations/keyframes to allow // animationStart to see each time a new node loads onto the bodyContent. function createObserver { // If .ready happens early (or animstart isn't supported), go ahead. // The "false" replacement is only needed for testing purposes. // When ready to deploy, remove false and uncomment isReady check. if( false /* $.isReady */ ) { return; // ??? How did we get $.isReady if bC or catlinks aren't loaded? } else { $( document ).ready( function { 			if( tabbedLanguages.length === 0 ) {				removeObserver;				allAtOnce;			}		}); }	// Check whether animations are even supported. If not, abort. // Basically yoinked from Modernizr. var supportsAnimations = false; $.each(		"animationName WebkitAnimationName MozAnimationName OAnimationName msAnimationName".split(" "),		function(a, b){			// Do documentElements even always have .style? If not, this'll need fixing.			if( document.documentElement.style[ b ] !== undefined ) {				supportsAnimations = true;				return false;			}		}	); if( supportsAnimations === false || !document.getElementsByClassName ) { return; }	var foundHeader = false, toc, recentChild, timer = false, // It's the setTimeout value, or false otherwise. recentHeader = -1, checkTab, tabFound = false, // If anyone on this project even considers making a random element // on a page have the class "visualClear"... visualClear = document.getElementsByClassName( "visualClear" ), languageContainer; // TODO: Deal with the little jumping elements below the tabstable. // ...How? /*		"@/@-moz-/@-webkit-/@-ms-/@-o-/".split("/") .join("keyframes nodeInserted{" +				"from{outline-color:#fff;}" +				"to{outline-color:#000;}" +			"}\n"); */	observerStyleSheet = mw.util.addCSS( 		"@keyframes nodeInserted{from{outline-color:#fff;}to{outline-color:#000;}}" + 		"@-moz-keyframes nodeInserted{from{outline-color:#fff;}to{outline-color:#000;}}" + 		"@-webkit-keyframes nodeInserted{from{outline-color:#fff;}to{outline-color:#000;}}" + 		"@-ms-keyframes nodeInserted{from{outline-color:#fff;}to{outline-color:#000;}}" + 		"@-o-keyframes nodeInserted{from{outline-color:#fff;}to{outline-color:#000;}}" + 		".mw-content-ltr>*,.mw-content-ltr+*,.visualClear{" + /* "background:#FF6A6A;" + */			"animation-duration:0.01s;-o-animation-duration:0.01s;-ms-animation-duration:0.01s;" + 			"-moz-animation-duration:0.01s;-webkit-animation-duration:0.01s;" + 			"animation-name:nodeInserted;-o-animation-name:nodeInserted;-ms-animation-name:nodeInserted;" + 			"-moz-animation-name:nodeInserted;-webkit-animation-name:nodeInserted;" +		"}"	); document.addEventListener('animationstart', animFound, false); document.addEventListener('MSAnimationStart', animFound, false); document.addEventListener('webkitAnimationStart', animFound, false); function animFound { if( timer === false ) { timer = setTimeout( function {				timer = false;				reactToObserver;			}, 1); }	}	function reactToObserver { // TODO: Surround main areas in try{} so that if it breaks, at least // the content gets dumped back into visibility. console.log("reactToObserver"); // First: What part are we up to? if( !foundHeader ) { // search for header or toc if( !recentChild ) { // Just starting, apparently. if( !bodyContent ) { bodyContent = $(".mw-content-ltr")[0]; if( !bodyContent ) { // Somehow ended up here before bC loaded. // Probably a result of someone else's animation. return; }				}				// Check if we can do the whole thing in one go. if( visualClear.length ) { removeObserver; allAtOnce; return; }				recentChild = bodyContent.firstChild; if( !recentChild ) { return; // Somehow got activated between bodyContent load // and bodyContent's content's load. }			}			for(!isHeader( recentChild ) && recentChild.nextSibling; ) { recentChild = recentChild.nextSibling; }			if( isHeader( recentChild ) ) { // should simplify check. Maybe !recentChild.nextSibling? // We have our first header. foundHeader = true; console.log( "Found header" ); checkTab = setUpHashChange; // Default to the first tab. currentLanguageTab = 0; toc = document.getElementById('toc'); if ( toc ) { if ( toc.nextSibling ) { // And we have a usable ToC. Makes things much easier. // Analyze the ToC. We'll be using it to determine what // the tabs are going to be. $( ".toclevel-1 > a > .toctext" ).each( function { 							var language = $( this ).text;							tabbedLanguages.push( language );						}); // Build all the tabs. $( tabbedLanguages ).each( newTab ); toc.parentNode.removeChild( toc ); // Afterwards, we'll check if the right section // is already available. } else { // Potential panic situation: Evil formatting places // ToC *after* the first header, so it's actually // *partly* loaded at this point, with no nextSibling. // (Alternatively, someone put it alone in a box.) CSS // builds it up as a huge tabbing block, but we can't // remove it here. Oy. // "Solution": // Temporarily hide the ToC until ready fires, then // remove it. I'm not removing it right away, as I have // no idea what doom might occur if something like this // is removed while stuff is being loaded into it. toc.style.display = "none"; ( function ( toc ) {							$( function { if( toc.parentNode ) { toc.parentNode.removeChild( toc ); }							});						})( toc ); toc = undefined; window.console && console.error( "TL notice: " +							"Malformed entry. ToC either appears after " + 							"headers, or is placed in a box. Mind fixing " +							"it or alerting me? Thanks. -- YR" ); }				}				languageContainer = languageContainers[ 0 ]; // Edit buttons. processEditButton( 					recentChild.getElementsByTagName( "span" )[ 1 ]				); // Either way, start displaying the tabs right. bodyContent.insertBefore( tabstable, recentChild ); if( toc ) { tabFound = checkTab; }			}		}		if( foundHeader ) { // Note that there may or may not be a ToC available... // Should this be reworked so that the toc check is inside the loop? if( recentChild.nextSibling ) { // I hope I'm not going to regret leaving out a recentChild && condition here... for( var lastChild = bodyContent.lastChild, nextChild; recentChild !== lastChild; ) { nextChild = recentChild.nextSibling; if( isHeader( recentChild ) ) { var spans = recentChild.getElementsByTagName('span'); if( recentHeader >= 0 ) { languageContainer.insertBefore( bodyContentFragment, languageContainer.lastChild ); }						recentHeader++; var language = ( language = spans[0] ).innerText || language.textContent; // Make sure it actually matches, when necessary. if( toc && language !== tabbedLanguages[ recentHeader ]) { // PANIC!!! // Okay, maybe don't panic. TL has encountered // a header that doesn't match the ToC's // description of the page. Possibilities // include an h1 on the page, a fake header // around somewhere, or some other malformed // kind of header. This really isn't supposed // to happen ever. // Response: Clear everything after this point, // and from there act as though the ToC never // existed. if( recentHeader > 0 ) { toggleLanguageTabs( tabbedLanguages[ 0 ] ); } else { currentLanguageTab = 0; }							while( tabbedLanguages.length > recentHeader ) { tabbedLanguages.pop; ttr.removeChild( 									languageContainers.pop								); languageLinks.removeChild( 									languageButtons.pop.parentNode								); }							toc = undefined; // Never. Existed. tabFound = false; window.console && console.error( "TL notice: " + 								"Malformed entry. ToC does not match " +								"headers. Possibly a misplaced H1, fake " +								"header, or header with incorrect " + 								"contents. Mind fixing it or " +								"alerting me? Thanks. -- YR "							); }						if( !toc ) { tabbedLanguages.push( language ); newTab( recentHeader, language ); }						// Check to see if the target tab is found. // TODO: Need a better system of knowing when to check: //  If it's found, stop checking. //  Whether or not we have a ToC, checking can be necessary. //  If we do have a ToC, but no hash, we don't check, right? //  Put another way: //    No hash? W/ ToC, don't check. W/o ToC, only check when new headers come in. //    Hash? Depends. //      W/ ToC: Technically, target could come in at any non-header element... ??? //      W/o ToC: Could be whenever. Target header coming in is rather likely, in fact. Oy. //      Either way: If the target, whether header or random element, is found, stop looking. //    Does delaying the tab switch to a element target until full load matter? Not sure. //  						//	Plan B: Regardless of ToC presence, only //	check for potential target elems //	at each new header, unless target is found. if( recentHeader > 0 && tabFound === false ) { tabFound = checkTab; }						languageContainer = languageContainers[ recentHeader ]; if( recentHeader > 0 ) { // I have too many of these checks... // Don't duplicate earlier pEB for first header. processEditButton( spans[ 1 ] ); }						// All done. Clear. bodyContent.removeChild( recentChild ); } else { if( recentChild.nodeName === "HR" ) { // Kill unnecessary bars. bodyContent.removeChild( recentChild ); } else { // Regular content. Prepare for dumping into the // latest tab. bodyContentFragment.appendChild( recentChild ); }					}					recentChild = nextChild; }			}			// If we're all done, finish up. // How to tell? // Option one: Repeatedly check for nextSibling. // 	 - Won't work. bodyContent doesn't always have a nS at the end. //  - Currently in use only for dealing with the last elem. (Uses O2 as fallback.) // Option two: Set up getElemsByClassName, and poll for length. //	 - presumably visualClear. This would probably be pretty heavy. //  - Currently in use. // Option three: Use $.ready. //	 - Potentially introduces substantial delay... // Option four: In the listener, check for classnames each time. //	 - Every time there's a new node? Lots of processing. // Option five: ... if( bodyContent.nextSibling ) { // are we done? ...				// bodyContent.nextSibling doesn't always exist, but if it // does, get a head start on the stuff that can be done already. console.log( recentChild, recentChild.nextSibling, recentChild.parentNode ); bodyContentFragment.appendChild( bodyContent.lastChild ); }			// Dump collected elems into most recent languageContainer. if( bodyContentFragment.firstChild ) { // Exact duplicate of above code. TODO: Fix. languageContainer.insertBefore( bodyContentFragment, languageContainer.lastChild ); }			if( visualClear.length ) { if( bodyContent.lastChild === recentChild ) { // bC.nS didn't exist. Move the last one left now. languageContainer.insertBefore( bodyContent.lastChild, languageContainer.lastChild ); }				removeObserver; sortCats; // complete = true; // Not actually used anywhere here... if( tabFound !== true ) { checkTab; if( location.hash === '' ) { location.replace( "#" + tabbedLanguages[currentLanguageTab] ); }				}			}		}	}	function removeObserver { document.removeEventListener('animationstart', animFound, false); document.removeEventListener('MSAnimationStart', animFound, false); document.removeEventListener('webkitAnimationStart', animFound, false); if( observerStyleSheet ) { observerStyleSheet.disabled = true; }		if( timer !== false ) { clearTimeout( timer ); }	} }

function isHeader( elem ) { return elem && elem.nodeName === "H2" && elem.getElementsByTagName( "span" ).length !== 0; }

function newTab( index, language ) { var active = index === currentLanguageTab; var languageContainer = ttr.appendChild( newNode('td', { 'class': 'languageContainer', 'id': language + 'container' }, active ? undefined : { 'style' : 'display:none;' } )); languageContainers.push( languageContainer ); newCategoryBox( languageContainer, language ); // lB contains .(un)?selectedTab nodes languageButtons.push(		languageLinks.appendChild( newNode('tr', newNode('td', { 'class': ( active ? '' : 'un' ) + 'selectedTab' }, newNode('a', language, {			// Note: ' + language' makes this inconsistent with the ordinary links 			// themselves, which have the language name encoded. Issue?			// Keep in mind that the parser itself actually corrects for this, 			// changing #!Xóõ links to the proper #.C7.83X.C3.B3.C3.B5 links.			// Probably nothing to worry about.			'href': location.pathname + location.search + '#' + language		}), ' '))).firstChild	); }

function newCategoryBox( container, name ) { // Put a container in each for categories. return container.appendChild( newNode('div', name + ' categories: ', newNode('ul'), { 'class': 'catlinks', 'id': 'catlinks' })); }

function processEditButton( button ) { if( button ) { // Yes, theoretically if you have some fake H2s the edit buttons will // be misplaced. Yet another TODO... var len = languageHeaderEditButtons.push( button ); if( len === 1 ) { caption = document.createElement('caption'); tabstable.insertBefore( caption, tabstable.firstChild ); }		button.className += " editlangsection"; // use a argument or variable ( from .push? ) instead of .length? if( len - 1 === currentLanguageTab ) { caption.firstChild && caption.removeChild( caption.firstChild ); caption.appendChild( button ); }	} }

// Sets up the hash toggle system. // Returns the checkTab function, which returns true if // we found whatever it was. function setUpHashChange { // Important Note: The decodeURI mess is a real mess. // #.C7.83X.C3.B3.C3.B5 should go to tab "!Xóõ", with // the id "!Xóõcontainer" (no encoding). Urgh. // Also, "#Old_English" needs to go to decoded "Old English". // Remember to .substr( 1 ) before passing here. function decodeHash( hash ) { return decodeURI(			hash				.replace(/\.(?=[0-9A-F]{2})/g, '%')				.replace(/_/g, ' ')		); }	// Called by onhashchange. function hashToggleLT { var destination = decodeHash( location.hash.substr(1) ); toggleLanguageTabs( destination ); tabbedLanguages[currentLanguageTab] !== destination && resetHash; }	// For updating page positioning. // Doesn't activate hashchange, at least in Chrome. Not sure about others. function resetHash { location.replace( location.hash ); }	// Need to decide if language arg is encoded or decoded. // Will work with either for the moment. Decoded works earlier. // Currently passed as decoded by every function but itself. // The hashes are encoded, but hashToggleLT decodes them. // Toggles to a different language tab. window.toggleLanguageTabs = function (language) { // Find the destination language. var destinationLanguageTab = $.inArray( language, tabbedLanguages ); if( destinationLanguageTab === -1 ) { var decoded = decodeHash( language ); if( decoded !== language ) { destinationLanguageTab = $.inArray( decoded, tabbedLanguages ); }		}		// Style the right toggle button, hide the old language section and show the new one. // var languageButtons = $("#languageLinks .selectedTab, #languageLinks .unselectedTab"); if (destinationLanguageTab !== -1 ) { if( destinationLanguageTab !== currentLanguageTab ) { languageButtons[currentLanguageTab].className = 'unselectedTab'; languageContainers[currentLanguageTab].style.display = 'none'; currentLanguageTab = destinationLanguageTab; languageButtons[destinationLanguageTab].className = 'selectedTab'; languageContainers[destinationLanguageTab].style.display = ''; if (caption) { // extra checks shouldn't be necessary... caption.firstChild && caption.removeChild(caption.firstChild); languageHeaderEditButtons[currentLanguageTab] && caption.appendChild(languageHeaderEditButtons[currentLanguageTab]); }

if (isIE9) { for (var ols = languageContainers[currentLanguageTab].getElementsByTagName('ol'), i = 0; i < ols.length; i++) { (function (i) {							setTimeout(function { ols[i].removeChild(ols[i].insertBefore(document.createElement('li'), ols[i].firstChild)); }, 0);						})(i); }				}			}		} else { // Does the hash match the id of a node in a tab? language = encodeURI( language.replace(/\ /g, '_') ); // Yes, I just possibly undid the decoding from hashToggleLT. // Worse, this might double-encode, breaking things. // Or maybe not? I think everything might be decoded before being // sent here? // I'll deal with it later. // Find the node, and go up the node tree until // you hit .languageContainer, or nothing. language = document.getElementById( language ); for(language && ( language = language.parentNode ) && 				language.className !== 'languageContainer'; ) ;			// language = language && language.parentNode.parentNode; if ( language /* && language.className === 'languageContainer' */ ) { // If someone maliciously makes a languageContainer with a // non-compliant ID, boom. toggleLanguageTabs( language.id.split('container')[0] ); }			// Possible doom bug: Endless loop? }	};	// This function gets returned as checkTab, btw. // For during or immediately after load: Check if we have a // good "starting" tab. Return true if we have a definitive find. function checkTab { // 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 subsection or 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 there's no hash at all, work off of the localStorage and TT prefs. console.log( "checkTab" ); try { if ( location.hash !== '' ) { var hash = ( location.hash ).substr( 1 ); // does hash.substr always exist? var destination = decodeHash( hash ); // 'k, this is still awful. if( $.inArray( destination, tabbedLanguages ) !== -1 ) { toggleLanguageTabs( destination ); window.scrollY && window.scroll(0, 0); return true; } else if ( document.getElementById( hash ) ) { // This was going // to receive an area to search from an argument, but it turns // out that elem.getElementById doesn't actually exist. Meh. toggleLanguageTabs( destination ); resetHash; // Scroll to the element. (Necessary since we 					// this isn't running through hashToggleLT, which normally does					// it in these situations.) return true; }			}			// No hash. Work from localStorage and TT. if ('localStorage' in window) { var ind = $.inArray(localStorage.langTabPref, tabbedLanguages); if ( ind !== -1 ) { toggleLanguageTabs( tabbedLanguages[ ind ] ); } else if (tabbedLanguages[0] !== 'Translingual' && tabbedLanguages[0] !== 'English' && localStorage.TargetedTranslations) { for (						var tt_ = localStorage.TargetedTranslations.split("|"), tt = tt_[0].split(";").concat( $.grep(								tt_[1].replace(/[^;\/]+\//g, '').split(";"), 								function (z) {									return z && z !== "Latin" && z !== "Hebrew" && z !== "Arabic";								}							) ).concat( tt_[1].replace(/\/[^;]+/g, '').split(";") ), i = 0; 						i < tt.length;						i++					) { if ($.inArray(tt[i], tabbedLanguages) !== -1) { toggleLanguageTabs(tabbedLanguages[$.inArray(tt[i], tabbedLanguages)]); break; }					}				}			}			return false; } catch ( e ) { // This probably isn't all that unlikely to happen. Too complicated. :(			window.console && console.log( "TL error: checkTab broke.", e );		}	}	if ("onhashchange" in window && (document.documentMode === undefined || document.documentMode > 7)) {		window.onhashchange = hashToggleLT;	} else {		$( bodyContent ).on( 'click', 'a[href^="' + location.pathname + location.search + '#"], a[href^="#"]', function { setTimeout( hashToggleLT, 10 ); }		);	}	if ('localStorage' in window) {		window.onunload = function {			if (tabbedLanguages[currentLanguageTab]) {				localStorage.langTabPref = tabbedLanguages[currentLanguageTab];			}		};	}	// checkTab;	return checkTab; }

function sortCats { var catDiv = document.getElementById('mw-normal-catlinks'), z,		currentCatDiv; if (catDiv) { var cats = catDiv.getElementsByTagName('li'), catname, langcurrent = 0, catskip = 1; do { while (cats.length > 0) { z = 0; catname = cats[z].getElementsByTagName('a')[0].innerHTML; if (catname.indexOf(tabbedLanguages[langcurrent + catskip]) === 0 && 					!/letter\snames$|script\scharacters$|mythology$/.test(catname)				) { langcurrent += catskip; catskip = 1; }				while (z--+1) { currentCatDiv = languageContainers[langcurrent].lastChild; currentCatDiv.lastChild.appendChild(cats[0]); }			}			if (langcurrent + 1 < languageContainers.length - catskip) { while (currentCatDiv.lastChild.firstChild) { catDiv.lastChild.appendChild(currentCatDiv.lastChild.firstChild); }				catskip++; } else { break; }		} while (true); }	// place patrol link at the bottom of the page var pl = currentCatDiv.previousSibling; // languageContainer.lastChild.previousSibling; console.log( 555, pl, tabstable.parentNode, tabstable.parentNode.childNodes ); // Got it, the patrollink is sometimes the lagging last elem. if( pl && pl.className === "patrollink" ) { tabstable.parentNode.appendChild(pl); }	/*	// category editing buttons if (mw.config.get('wgAction') === "view" && !/&printable=yes|&diff=|&oldid=/.test(location.search)) { for (z = 0; z < languageContainers.length; z++) { // TODO: import // addTabbedLanguageNewCatButton(z); }		if ( window.loadremovecatbuttons === true ) { $.get(				mw.config.get( 'wgScript' ),				{ 'title' : mw.config.get('wgPageName'), 'action' : 'raw' },				// Note that this isn't actually defined. I'm considering not 				// actually importing the function, and just dumping this section.				addRemoveCatButtons 			); }	}	*/	// Remove old cat box, allow display of hidden cats box. if (catDiv && !(catDiv.nextSibling && catDiv.nextSibling.className === "mw-hidden-catlinks mw-hidden-cats-user-shown")) { catDiv.parentNode.parentNode.removeChild(catDiv.parentNode); } else { if (catDiv) { catDiv.parentNode.removeChild(catDiv); }	} }

/** * newNode imported from Mediawiki:Common.js. * * Create a new DOM node for the current document. *   Basic usage:  var mySpan = newNode('span', "Hello World!") *   Supports attributes and event handlers*: var mySpan = newNode('span', {style:"color: red", focus: function{alert(this)}, id:"hello"}, "World, Hello!") *   Also allows nesting to create trees: var myPar = newNode('p', newNode('b',{style:"color: blue"},"Hello"), mySpan) * * *event handlers, there are some issues with IE6 not registering event handlers on some nodes that are not yet attached to the DOM, * it may be safer to add event handlers later manually. function newNode(tagname){ var node = document.createElement(tagname); for (var i = 1; i < arguments.length; ++i){ if (typeof arguments[i] == 'string') { // text node.appendChild(document.createTextNode(arguments[i])); } else if (typeof arguments[i] == 'object') { if (arguments[i].nodeName) { //If it is a DOM Node node.appendChild(arguments[i]); } else { // Attributes (hopefully) for (var j in arguments[i]){ if (j == 'class') { //Classname different because... node.className = arguments[i][j]; } else if (j == 'style') { //Style is special node.style.cssText = arguments[i][j]; } else if (typeof arguments[i][j] == 'function') { //Basic event handlers newNode.addEventHandler(node, j, arguments[i][j]); } else { node.setAttribute(j, arguments[i][j]); //Normal attributes }				}			}		}	}	node.addEventHandler = function(eventName, handler) { newNode.addEventHandler(this, eventName, handler); };	return node; } newNode.addEventHandler = function(node, eventName, handler) {	try{ node.addEventListener(eventName,handler,false); //W3C }catch(e){try{ node.attachEvent('on'+eventName,handler,"Language"); //MSIE }catch(e){ node['on'+eventName]=handler; }} //Legacy };

function testStuff { var delay = 5000, f = document.createDocumentFragment; var x = [ function { // $("#toc").remove; var x = document.getElementById( "mw-content-text" ); while( x.nextSibling ) { f.appendChild( x.nextSibling ); }		}, function { var y = $( ".mw-content-ltr" )[ 0 ]; var q = document.createDocumentFragment; while( y.firstChild ) { q.appendChild( y.firstChild ); }			function u( i, e ) { setTimeout( function {					y.appendChild( q.firstChild );				}, i / e * delay ); }			for( var i = 0, e = q.childNodes.length; i < e; i++ ) { u( i, e ); // encapsulate }			makeTabsfromScratch; }, function { setTimeout( function{				$(".mw-content-ltr").after( f );			}, 1000 ); console.log(9); }	];	x[0]; for( var i = 1; i < x.length; i++ ) { setTimeout( x[ i ], (i-1) * delay + 50 ); } }

//testStuff; makeTabsfromScratch;

// This is officially deprecated as of MW1.22. Should be replaced by mw.hook, // but the docs don't say what event, so... $(mw).bind('LivePreviewDone', function {	bodyContent = $(".mw-content-ltr")[0]; // reset	makeTabsfromScratch; });

})( window.jQuery );