Pengguna:Bennylin/TabbedLanguages2.js

Catatan: Setelah disimpan, Anda mungkin perlu melewati tembolok peramban web untuk melihat perubahan.

  • Firefox/Safari: Tekan dan tahan Shift sembari mengeklik Reload, atau tekan Ctrl-F5 atau Ctrl-R (⌘-R di Mac)
  • Google Chrome: Tekan Ctrl-Shift-R (⌘-Shift-R di Mac)
  • Internet Explorer / Edge: Tahan Ctrl sembari mengeklik Refresh, atau tekan Ctrl-F5
  • Opera: Tekan Ctrl-F5.
// This is a (very) modified version of User:Atelaes/TabbedLanguages.js.
// Tabbed languages with tabs on the side.
// Tabs design by [[User:Jorm (WMF)]]
// Code still needs cleaning up
var tabbedLanguages = tabbedLanguages || [],
	languageContainers = languageContainers || [],
	currentLanguageTab = currentLanguageTab || 0,
	languageHeaderEditButtons = languageHeaderEditButtons || [],
	tocLangSections, tabstable, loadremovecatbuttons = true;

function makeLanguageTabs() {
	if (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")
		//    mw.util.addCSS("#tabstable{clear:both;}#languageLinks .selectedTab a{font-size:19px;color:#000;padding:6px;display:block;border-left:1px solid #AAA;border-bottom:1px solid #AAA;margin-bottom:-3px;background-color:#fff;margin-right:-6px;position:relative;border-top:1px solid #aaa;white-space:nowrap;}.unselectedTab a{font-size:16px;color:#AAA;padding:6px;display:block;border-left:1px solid #AAA;border-top:1px solid #AAA;border-bottom:1px solid #AAA;margin-bottom:-3px;margin-left:15px;margin-right:-5px;white-space:nowrap;background-color:#F3F3F3;}#languageLinks tr td{padding:0px;}tr td.languageContainer{padding-left:8px;padding-bottom:10px;padding-right:8px;border:1px solid #AAA;vertical-align:top;width:100%;}.unselectedtab{margin-left:5px;}.editlangsection{margin-top:-13px;margin-right:5px;border:1px solid #AAA;margin-bottom:-2px;border-bottom-width:0px;-webkit-border-top-left-radius:5px;-webkit-border-top-right-radius:5px;-moz-border-radius-topleft:5px;-moz-border-radius-topright:5px;border-top-left-radius:5px;border-top-right-radius:5px;color:white;line-height:14px;font-size:12px;padding:0px 7px;text-align:center;clear:both;background-color:white;}")
		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
//document.getElementById('wikiPreview') || document.getElementById('bodyContent') || document.getElementById('mw_contentholder') || document.getElementById('article') || document.getElementById('content');

		// 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, rm the old toc and add 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';
				if (document.getElementById('toc')) {
					tocLangSections[currentLanguageTab].style.display = 'none';
					tocLangSections[destinationLanguageTab].style.display = 'list-item';
				}
				currentLanguageTab = destinationLanguageTab
				languageButtons[destinationLanguageTab].className = 'selectedTab'
				languageContainers[currentLanguageTab].style.display = 'table-cell';
				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 && (language = (language = spans[1] && spans[1].className == 'mw-headline' && languageHeaderEditButtons.push(spans[0]) && spans[1] || 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) {
			try {
				VisibilityToggles.register('TOC', function () {
					toc.style.display = 'table';
				}, function () {
					toc.style.display = 'none';
				});
			} catch (e) {
				toc.style.display = 'none';
			}
		}
		if (tabbedLanguages.length > 0) {
			try {
				if (toc) {
					if (toc.getElementsByClassName) {
						tocLangSections = toc.getElementsByClassName('toclevel-1');
						for (var c = 1; c < tocLangSections.length; c++) {
							tocLangSections[c].style.display = 'none'
						}
					} else {
						tocLangSections = []
						for (var c = 0, temptocbox = toc.getElementsByTagName('ul')[0]; c < temptocbox.childNodes.length; c++) {
							if (temptocbox.childNodes[c].nodeName == "LI") {
								if (tocLangSections.length) temptocbox.childNodes[c].style.display = 'none';
								tocLangSections.push(temptocbox.childNodes[c])
							}
						}
					}
				}
				// 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', 'Tambah bahasa', {
						'style': 'font-size:12px;padding:3px 6px;',
						'click': newLanguageTab,
						'title': 'Tambahkan bagian bahasa baru'
					}))));
					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;
							while (catname.indexOf("derivations") > 0 && cats.length > z + 1) {
								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.childNodes[1]) {
								catDiv.lastChild.appendChild(currentCatDiv.childNodes[1]);
							}
							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-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
				tocLangSections = toc.getElementsByClassName('toclevel-1');
				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 = hash.replace(/_/g, ' ');
				toggleLanguageTabs(destination);
				if (document.getElementById(hash)) {
					resetHash()
				} else {
					window.scrollY && window.scroll(0, 0);
				}
			} else {
				if (tabbedLanguages[0] != 'Translingual' && tabbedLanguages[0] != 'English' && 'localStorage' in window) {
					if ($.inArray(localStorage.langTabPref, tabbedLanguages) != -1) {
						toggleLanguageTabs(tabbedLanguages[$.inArray(localStorage.langTabPref, tabbedLanguages)])
					} else if (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;
							}
						}
					}
				}
			}
			if ("onhashchange" in window) {
				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] && tabbedLanguages[currentLanguageTab] != 'English' && tabbedLanguages[currentLanguageTab] != 'Translingual') {
						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': 'Tambah'
				}), newNode('input', {
					'type': 'button',
					'value': 'Batal',
					'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('[[:Kategori:' + values.category + '|' + 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[" + "[Kategori:" + 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': '+[' + '[Kategori:' + 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;',
		'title': 'Tambah kategori baru'
	})))
}

function hashToggleLT() {
	var destination = decodeURI(location.hash.substr(1)).replace('_', ' ');
	toggleLanguageTabs(destination);
}

function resetHash() {
	window.scroll(0, $(location.hash).offset().top)
}

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: 'Nama bahasa',
		title: 'Nama bahasa'
	}), newNode('br'), newNode('input', {
		type: 'submit',
		style: 'width:50%;',
		value: 'Tambah'
	}), newNode('input', {
		type: 'button',
		style: 'width:50%;',
		click: function () {
			languageLinks.removeChild(languageLinks.lastChild.previousSibling);
			languageLinks.lastChild.style.display = null
		},
		value: 'Batal'
	}))))), 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()
				}
			}
		}
	}

	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'
		}))
		var toc = document.getElementById('toc') ? document.getElementById('toc').getElementsByTagName('ul')[0] : null;
		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)
				})));
				toc && toc.appendChild(newNode('li', {
					'class': 'toclevel-1'
				}));
				if (toc && tocLangSections.push) tocLangSections.push(toc.lastChild);
				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()
				if (toc && tocLangSections.push) tocLangSections.pop();
				toc && toc.removeChild(toc.lastChild);
				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: 'Hapus kategori ini',
			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: 'Ubah',
			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': 'Ubah'
						}), newNode('input', {
							'type': 'button',
							'value': 'Batal',
							'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('[[:Kategori:' + values.category + '|' + 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]) + "([\\|\\]])"), "[" + "[Kategori:" + 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] + ']] > [' + '[Kategori:' + values.category + ']]'
							}, newCat)
						})
					}
				}, qq)
				addCatForm.firstChild.focus()
			}
		}))
	}
	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])
			}
		}
	}
}

jQuery(document).ready(makeLanguageTabs);