User:Yair rand/TabbedLanguagesposteditlinkexplosionversion.js

// On May 1, the editlinks HTML is going to be modified, which will cause some scripts, including TL, to break. This version will be copied over to MediaWiki:Gadget-TabbedLanguages.js after the deployment.

// This is a (very) modified version of User:Atelaes/TabbedLanguages.js. // Tabbed languages with tabs on the side. // Tabs design by User:Jorm (WMF)

window.tabbedLanguages = []; window.languageContainers = []; window.currentLanguageTab = 0; window.languageHeaderEditButtons = []; window.tabstable = undefined; window.loadremovecatbuttons = false;

function makeLanguageTabs($) { if ((mw.config.get('wgNamespaceNumber') == 0 || mw.config.get('wgPageName') == "Wiktionary:Sandbox") && mw.config.get('wgAction') != 'edit' && $.cookie('disable-tabbed-languages') == null && location.search.indexOf("tabbedlanguages=off") == -1 && !window.loadedTabs) { window.loadedTabs = true; //   importStylesheet("User:Yair_rand/TabbedLanguages.css") var languageContainer, li, language, toc = document.getElementById('toc'), languageLinks, ttr, catDiv = document.getElementById('mw-normal-catlinks'), isIE9, bodyContent_ = $(".mw-content-ltr")[0]; // hopefully temporary fix, supposed to be document.getElementById('mw-content-text');

if( !bodyContent_ ){return}

// Dump everything into a documentfragment, to be put back at the end (this is somehow faster, I don't know why) var bodyContent = document.createDocumentFragment; while (bodyContent_.firstChild) bodyContent.appendChild(bodyContent_.firstChild); 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.toggleLanguageTabs = function (language) { // Find the destination language. for (var destinationLanguageTab = tabbedLanguages.length - 1; destinationLanguageTab >= 0; destinationLanguageTab--) { if (language.indexOf(tabbedLanguages[destinationLanguageTab]) == 0) { break; }			}			// Style the right toggle button, hide the old language section and show the new one. // var languageButtons = document.getElementById('languageLinks').getElementsByTagName('span'); var languageButtons = $("#languageLinks .selectedTab, #languageLinks .unselectedTab"); if (destinationLanguageTab >= 0) { languageButtons[currentLanguageTab].className = 'unselectedTab'; languageContainers[currentLanguageTab].style.display = 'none'; currentLanguageTab = destinationLanguageTab languageButtons[destinationLanguageTab].className = 'selectedTab' languageContainers[currentLanguageTab].style.display = ''; if (languageHeaderEditButtons.length) { tabstable.parentNode.removeChild(tabstable.previousSibling) tabstable.parentNode.insertBefore(languageHeaderEditButtons[currentLanguageTab], tabstable) }

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 if ((language = language.replace(/\ /g, '_')) && document.getElementById(language) && document.getElementById(language).parentNode.parentNode.className == 'languageContainer') { toggleLanguageTabs(document.getElementById(language).parentNode.parentNode.id.split('container')[0]) }		}		// Look through all the nodes in bodyContent, placing them in the correct language containers. for (var child = bodyContent.firstChild; child && (child.nodeName != "H2" || child.getElementsByTagName('span').length == 0); child = child.nextSibling); for (child = child && bodyContent.insertBefore(tabstable, child).nextSibling; child && child.className != 'printfooter' && child.className != 'catlinks'; child = child.nextSibling) { if (child.nodeName == 'H2') { var spans = child.getElementsByTagName('span'); if (spans.length != 0 && ( spans[1] && languageHeaderEditButtons.push(spans[1]), language = (language = spans[0]).innerText || language.textContent)) { tabbedLanguages.push(language); languageContainers.push(languageContainer = ttr.appendChild(newNode('td', {						'class': 'languageContainer',						'id': language + 'container'					}))); bodyContent.removeChild(child); child = tabstable }			} else { child.nodeName != "HR" ? languageContainer.appendChild(child) : bodyContent.removeChild(child); child = tabstable }		}		if(toc) { toc.parentNode.removeChild(toc) }		if (tabbedLanguages.length > 0) { try { // Make the toggle. for (var b = 0; b < tabbedLanguages.length; b++) { language = tabbedLanguages[b]; languageLinks.appendChild(newNode('tr', newNode('td', {						'class': (b ? 'un' : '') + 'selectedTab'					}, newNode('a', language, { 'href': location.pathname + location.search + '#' + language }), ' ')))				}				// If there are section edit links, add edit link, and a new language button. if (languageHeaderEditButtons.length) { if (window.addPOSHeader) // this functionality requires adddefinition.js, editor.js, and TabbedLanguages.js at the same time languageLinks.appendChild(newNode('tr', newNode('td', {						'class': 'unselectedTab',						style: 'cursor:pointer;'					}, newNode('a', 'Add language', { 'class': 'addLanguageButton', 'click': newLanguageTab, 'title': 'Add new language section' }))));					for (var b = 0; b < languageHeaderEditButtons.length; b++) { languageHeaderEditButtons[b].className += " editlangsection" }					bodyContent.insertBefore(languageHeaderEditButtons[0], tabstable); }

for (var a = 0; a < languageContainers.length; a++) { languageContainer = languageContainers[a]; if (a != 0) { languageContainer.style.display = 'none'; }					// Put a container in each for categories. languageContainer.appendChild(newNode('div', languageContainer.id.split('container')[0] + ' categories: ', newNode('ul'), { 'class': 'catlinks', 'id': 'catlinks' }));				}				// Now for category sorting if (catDiv) { var cats = catDiv.getElementsByTagName('li'), catname, langcurrent = 0, catskip = 1; do { while (cats.length > 0) { var 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) { var 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) } /*     for(var z = 0; z < languageContainers.length; z++){ // rm topic cat prefixes languageContainers[z].lastChild.innerHTML = languageContainers[z].lastChild.innerHTML.replace(/\>[a-z]{2,3}(\-[a-z]{2,3})?\:/g,'>') // .replace(RegExp("\\>"+util.escapeRe(tabbedLanguages[z])+" ([a-z])","g"),function(jj,j){return ">"+j.toUpperCase}) }				// place patrol link at the bottom of the page var pl = languageContainer.lastChild.previousSibling; if(pl && pl.className == "patrollink"){ bodyContent.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++) { addTabbedLanguageNewCatButton(z) }					if (loadremovecatbuttons == true) { $.get(mw.config.get('wgScript'),{'title':mw.config.get('wgPageName'),'action':'raw'},addRemoveCatButtons) }				}				// rm 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); }				}				// put everything back into the bodyContent bodyContent_.appendChild(bodyContent); bodyContent = bodyContent_; } catch (e) { if (bodyContent_ != bodyContent) { 'console' in window && typeof console.log == "function" && console.log(e); bodyContent_.appendChild(bodyContent); bodyContent = bodyContent_; }			}			if (isIE9 = $.client.profile.name == "msie" && $.client.profile.versionNumber == 9) { // IE9 is EVIL toggleLanguageTabs(tabbedLanguages[currentLanguageTab]) }			// 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 (location.hash != '') { var hash = decodeURI(location.hash).substr(1); var destination = decodeURI(hash.replace(/\.(?=[0-9A-F]{2})/g, '%').replace(/_/g, ' ')); toggleLanguageTabs(destination); if (document.getElementById(hash)) { resetHash } else { window.scrollY && window.scroll(0, 0); }			} else { if ('localStorage' in window) { if ($.inArray(localStorage.langTabPref, tabbedLanguages) != -1) { toggleLanguageTabs(tabbedLanguages[$.inArray(localStorage.langTabPref, tabbedLanguages)]) } else if (tabbedLanguages[0] != 'Translingual' && tabbedLanguages[0] != 'English' && localStorage.TargetedTranslations) { for (var tt = localStorage.TargetedTranslations.split("|")[0].split(";").concat($.grep(localStorage.TargetedTranslations.split("|")[1].replace(/[^;\/]+\//g, ).split(";"), function (z) {							return z && z != "Latin" && z != "Hebrew" && z != "Arabic"						})).concat(localStorage.TargetedTranslations.split("|")[1].replace(/\/[^;]+/g, ).split(";")), i = 0; i < tt.length; i++) { if ($.inArray(tt[i], tabbedLanguages) != -1) { toggleLanguageTabs(tabbedLanguages[$.inArray(tt[i], tabbedLanguages)]); break; }						}					}				}                               location.replace( "#" + tabbedLanguages[currentLanguageTab] ); }			if ("onhashchange" in window && (document.documentMode === undefined || document.documentMode > 7)) { window.onhashchange = hashToggleLT; } else { jQuery(bodyContent_).delegate('a[href^="' + location.pathname + location.search + '#"], a[href^="#"]', 'click', function {					setTimeout(hashToggleLT, 10)				}) }			if ('localStorage' in window) { window.onunload = function { if (tabbedLanguages[currentLanguageTab]) { localStorage.langTabPref = tabbedLanguages[currentLanguageTab] }				}			}		} else { bodyContent_.appendChild(bodyContent); bodyContent = bodyContent_; }	} }

function addTabbedLanguageNewCatButton(z) { function addTabbedLanguageCatForm { editor = new Editor; var addCatForm; new AdderWrapper(		editor, {			'createForm': function {				return addCatForm = newNode('form', { 'style': 'display:inline;' }, newNode('input', {					'name': 'category'				}), newNode('input', {					'type': 'submit',					'value': 'Add'				}), newNode('input', {					'type': 'button',					'value': 'Cancel',					'click': function {						addCatForm.parentNode.style.display = 'none'					}				}))			},			'fields': {				'category': function (txt, error) {					if (txt.indexOf('derivations') > -1) {						return error("Please add derivations categories via the etymology section.")					};					if (tabbedLanguages.length > z && txt.indexOf(tabbedLanguages[z + 1]) == 0) {						return error("Please add categories to their proper sections.")					};					return util.validateNoWikisyntax('category', true)(txt, error)				}			},			'onsubmit': function (values, render) {				render( + values.category + , function (res) { var newCat = newNode('span'); newCat.innerHTML = res; editor.addEdit({						'edit': function (wikitext) {							return ccc = wikitext.replace(new RegExp("(((^|\n)==[^=][\\s\\S]*?){" + (z + 1) + "}[\\s\\S]*?)(?=(\n|$))"), "$1\n[" + "[Category:" + values.category + "]]")						},						'redo': function {							addCatForm.parentNode.insertBefore(newCat, addCatForm);							addCatForm.style.display = 'none';							addCatForm.parentNode.style.display = 'inline-block';						},						'undo': function  {							addCatForm.parentNode.removeChild(newCat);							addCatForm.style.display = 'inline'						},						'summary': '+[' + '[Category:' + values.category + ']]'					}, newCat.firstChild) })			}		}, languageContainers[z].lastChild.lastChild.insertBefore(newNode("li"), languageContainers[z].lastChild.lastChild.lastChild)) addCatForm.firstChild.focus }	languageContainers[z].lastChild.lastChild.appendChild(	newNode('li', newNode('a', '(+)', {		'click': addTabbedLanguageCatForm,		'style': 'cursor:pointer;display:none;',		'title': 'Add a new category'	}))) }

function hashToggleLT { var destination = decodeURI(location.hash.substr(1)).replace('_', ' '); toggleLanguageTabs(destination); tabbedLanguages[currentLanguageTab] != destination && resetHash; }

function resetHash { location.replace( location.hash ); }

function newLanguageTab { var languageLinks = document.getElementById("languageLinks") languageLinks.lastChild.style.display = 'none'; var newLanguageButton = languageLinks.insertBefore(	newNode('tr', newNode('td', {		'class': 'unselectedTab'	}, newNode('a', newNode('form', {		'style': 'display:inline;',		'class': 'unselectedTab'	}, newNode('input', { style: 'color:#AAA;font-size:16px;', placeholder: 'Language name', title: 'Language name' }), newNode('br'), newNode('input', { type: 'submit', style: 'width:50%;', value: 'Add' }), newNode('input', { type: 'button', style: 'width:50%;', click: function { languageLinks.removeChild(languageLinks.lastChild.previousSibling); languageLinks.lastChild.style.display = null },		value: 'Cancel' }))))), languageLinks.lastChild) newLanguageButton.getElementsByTagName('form')[0].onsubmit = function { newLanguageTab2(languageLinks.removeChild(newLanguageButton).getElementsByTagName('input')[0].value); return false }

newLanguageButton.getElementsByTagName('input')[0].focus var langsuggestlist = "\nEnglish" + ('localStorage' in window && localStorage.langTabPref ? '\n' + localStorage.langTabPref : ''), TTlangs = ('localStorage' in window ? localStorage.TargetedTranslations : getCookie('TargetedTranslations')); if (TTlangs) { langsuggestlist += "\n" + TTlangs.split("|")[0].replace(/;/g, "\n") + "\n" + TTlangs.split("|")[1].replace(/[^;\/]+\//g, '').replace(/;/g, '\n') }	// note: find or build some autocomplete function so that I don't have to rewrite it for every script newLanguageButton.getElementsByTagName('input')[0].onkeyup = function (e) { if (this.value.charAt(0) != this.value.charAt(0).toUpperCase) this.value = this.value.charAt(0).toUpperCase + this.value.substr(1); e = (e || event).keyCode; if (!(e >= 33 && e <= 40) && e != 8 && e != 46 && e != 27 && e != 16 && this.value) { if (langsuggestlist.indexOf('\n' + this.value) > -1) { if (this.setSelectionRange) this.setSelectionRange([this.value.length, this.value = langsuggestlist.match(RegExp(this.value + "[^\n]*"))][0], this.value.length); else if (this.createTextRange) { var z = this.createTextRange; z.moveEnd('character', 0 - z.move('character', [this.value.length, this.value = langsuggestlist.match(RegExp(this.value + "[^\n]*"))][0]) + this.value.length); z.select }			} else { var t = this, v = t.value; JsMwApi({action:'query',rawcontinue:'',generator:'allpages',gapnamespace:10,gapprefix:'langrev/'+v,gaplimit:3,prop:'revisions',rvprop:'content'},function(r){					if(r.query && r.query.pages && t.value == v){						var l={}, ll={};						for(var i in r.query.pages){							var rqp = r.query.pages[i];ll = rqp.title < ll.title?ll:rqp;l = rqp.title > l.title?l:rqp;						}						if(!r['query-continue'] && ll.title.indexOf(l.title) == 0){							if(l.title != "Template:langrev/"+v){								if (t.setSelectionRange){									t.setSelectionRange(t.value.length, (t.value = l.title.substr(17)).length);								} else if (t.createTextRange) {									var z = t.createTextRange;									z.moveEnd('character', 0 - z.move('character', [t.value.length, t.value = l.title.substr(17)][0]) + t.value.length);									z.select								}							}						}					}				}) }		}	}

function newLanguageTab2(languageName) { editor = new Editor; for (var tosearchfrom = languageContainers[languageContainers.length - 1].lastChild; tosearchfrom && !/h\d/i.test(tosearchfrom.nodeName);) { tosearchfrom = tosearchfrom.previousSibling }		var findnumberofheaders = Number(tosearchfrom.firstChild.getElementsByTagName('a')[0].href.split("&section=")[1]) var newbutton = newNode('tr', newNode('td', { 'class': 'selectedTab' }, newNode('a', languageName, {			'href': '#' + languageName		}))) var newsection = newNode('td', {			'class': 'languageContainer',			'id': languageName + "container"		}, newNode('h3', { 'style': 'display:none;' }, newNode('span', {			'class': 'editsection'		}, newNode('a', { 'href': '&section=' + (findnumberofheaders + 1) })), '...'), newNode('div', languageName + ' categories: ', { 'class': 'catlinks', 'id': 'catlinks' }, newNode('ul'))) editor.addEdit({			edit: function (wikitext) {				return ccc = wikitext + "\n{\{rfc-auto}}\n\n\n==" + languageName + "==\n"			},			redo: function {				languageContainers.push(tabstable.firstChild.firstChild.insertBefore(newsection, languageContainers[languageContainers.length - 1].nextSibling))				if (languageLinks == newLanguageButton.parentNode) languageLinks.removeChild(newLanguageButton);				tabbedLanguages.push(languageName)				languageLinks.insertBefore(newbutton, languageLinks.lastChild)				languageHeaderEditButtons.push(newNode('span', {					'class': 'editsection'				}, newNode('a', { href: '&section=' + (findnumberofheaders + 1) })));				location.hash = '';				toggleLanguageTabs(languageName);				languageLinks.lastChild.style.display = 'table-row'			},			undo: function {				toggleLanguageTabs(tabbedLanguages[tabbedLanguages.length - 2])				tabstable.firstChild.firstChild.removeChild(languageContainers.pop)				tabbedLanguages.pop				languageLinks.removeChild(newbutton)				languageHeaderEditButtons.pop				languageLinks.lastChild.style.display = 'none'				languageLinks.insertBefore(newLanguageButton, languageLinks.lastChild)			},			summary: "+section " + languageName		}, newsection) editor.withCurrentText(function {			addPOSHeader(true)			currentBoxToBeAdded.style.display = 'none';			newsection.insertBefore(currentBoxToBeAdded.firstChild, newsection.lastChild).firstChild.focus			addTabbedLanguageNewCatButton(languageContainers.length - 1)		}) } }

function addRemoveCatButtons(res) { function addRemoveCatButton(qq) { qq.appendChild(newNode('a', '(−)', { style: 'padding-left:4px; cursor: pointer;', title: 'Remove this category', click: function { editor = new Editor; editor.addEdit({					edit: function (wikitext) {						return ccc = wikitext.replace(RegExp("\\[\\[" + util.escapeRe(qq.firstChild.title.split(" (pa")[0]) + "(\\]\\]|\\|[^\\]]+\\]\\])"), "").replace(/\n\n\n/g, "\n\n") },					redo: function { qq.lastChild.style.display = qq.lastChild.previousSibling.style.display = 'none'; qq.style.border = "2px #F00 dashed"; qq.style.opacity = "0.6"; qq.style.backgroundColor = "#FEE" },					// not going to bother with opacity for IE bc it breaks everything else undo: function { qq.lastChild.style.display = qq.lastChild.previousSibling.style.display = 'inline'; qq.style.border = ""; qq.style.opacity = ""; qq.style.backgroundColor = "" },					summary: "-[" + "[" + qq.firstChild.title.split(" (pa")[0] + "]]",					after_save: function {						qq.style.backgroundColor = "#F00";						setTimeout(function  { qq.parentNode.removeChild(qq.nextSibling); qq.parentNode.removeChild(qq) }, 400)					}				})			}		}))		qq.appendChild(newNode('a', '(±)', { style: 'padding-left:4px; cursor: pointer;', title: 'Modify', click: function { qq.firstChild.style.display = qq.lastChild.style.display = qq.lastChild.previousSibling.style.display = 'none'; editor = new Editor; var addCatForm; new AdderWrapper(				editor, {					'createForm': function {						return addCatForm = newNode('form', { 'style': 'display:inline;' }, newNode('input', {							'name': 'category',							value: qq.firstChild.title.substr(9).split(" (pa")[0] }), newNode('input', { 'type': 'submit', 'value': 'Change' }), newNode('input', { 'type': 'button', 'value': 'Cancel', 'click': function { qq.removeChild(addCatForm); qq.firstChild.style.display = 'inline'; qq.lastChild.style.display = qq.lastChild.previousSibling.style.display = 'inline'; }						}))					},					'fields': { 'category': function (txt, error) { if (txt.indexOf('derivations') > -1) { return error("Please add derivations categories via the etymology section.") };							return util.validateNoWikisyntax('category', true)(txt, error) }					},					'onsubmit': function (values, render) { render( + values.category + , function (res) {							var newCat = newNode('span');							newCat.innerHTML = res;							editor.addEdit({ 'edit': function (wikitext) { return ccc = wikitext.replace(new RegExp("\\[\\[" + util.escapeRe(qq.firstChild.title.split(" (pa")[0]) + "([\\|\\]])"), "[" + "[Category:" + values.category + "$1")								},								'redo': function {									qq.insertBefore(newCat, addCatForm);									addCatForm.style.display = 'none'								},								'undo': function  {									qq.removeChild(newCat);									addCatForm.style.display = 'inline'								},								'summary': '[' + '[' + qq.firstChild.title.split(" (pa")[0] + ']] > [' + '[Category:' + values.category + ']]' }, newCat)						}) }				}, qq)				addCatForm.firstChild.focus			}		}))	}	try {		for (var i = 0; i < languageContainers.length; i++) {			for (var ii = 0, q = languageContainers[i].lastChild.getElementsByTagName('li'); ii < q.length; ii++) {				if (RegExp("\\[\\[" + util.escapeRe(q[ii].firstChild.title.split(" (pa")[0]) + "[\\]\\|]").test(res)) { addRemoveCatButton(q[ii]) }			}		}	} catch (e) { } }

jQuery(document).ready(makeLanguageTabs);