User:Mustafar29/common.js

// \n' + '\t \n' + // settings '\t \n' + '\t\t \n' + '\t\t\tNumber of rows:  \n' + '\t\t\tList mainspace only \n' + '\t\t\tSort by alphabetic order (note that using other modes may dramatically increase loading time) \n' + '\t\t\tSort by creation date (page ids)* \n' + '\t\t\t\n' + '\t\t\tSort by last edit \n' + '\t\t\tSort by most popular (requires Category Exhibition enabled) \n' + '\t\t\tSort by number of article comments \n' + '\t\t\tUse descending order \n' + '\t\t \n' + '\t\t \n' + '\t\t\t<svg width="12" height="12" style="margin-right: 4px;">\n' + '\t\t\t\t<style type="text/css"><![CDATA[@keyframes spin{to{transform:rotate(360deg);}}circle{animation: spin 1s linear infinite;transform-origin:6px 6px;}]]> \n' + '\t\t\t\t<circle cx="6" cy="6" r="5.5" fill="none" stroke="#999" stroke-dasharray="8.63937979737193 8.63937979737193" />\n' + '\t\t\t \n' + '\t\t\tloading...\n' + '\t\t \n' + '\t \n' + // error messages '\t \n' + '\t\tNo pages were found!\n' + '\t \n' + // nav result '\t \n' + '\t \n' + '\t \n' + '\t \n' + '\t \n' + '\t \n' + // lol what is this even... '\t \n' + '\t \n' + ' ';

/* ================================== *\		# global CatNav object management \* ================================== */	if (catnav._g instanceof Object) { // global CatNav is an object if (Array.isArray(catnav._g.storage)) { // import+export storage - base url to hosting wiki catnav.data.storage.url = catnav._g.storage[0]; catnav.data.storage.scriptPath = catnav._g.storage[1]; } else if (catnav._g.hasOwnProperty("storage")) { console.error("catnav :: global 'CatNav.storage' has been defined, but it is not a valid array"); }	} else { // window.CatNav has not been defined - define it		window.CatNav = {}; }

/* ================================== *\		# functions \* ================================== */

/* functions for getting info about categories */

// get members of a given category catnav.fn.catMembers = function(cat, ns, arr, cont, cb) { /*		catnav.fn.getMembersOfCat("Foo", 0, [], "", function(data) {			console.log(data);		}); */		var req = new XMLHttpRequest; req.open("get", mw.config.get("wgScriptPath") + "/api.php?action=query&format=json&list=categorymembers&cmtitle=Category:" + encodeURIComponent(cat) + "&cmnamespace=" + ns + "&cmcontinue=" + encodeURIComponent(cont) + "&cmlimit=max&cb=" + new Date.getTime, true); req.onload = function { var data = JSON.parse(this.responseText); if (data.hasOwnProperty("query")) { var a = data.query.categorymembers; for (var i in a) { arr.push(data.query.categorymembers[i].title); }				if (typeof data["query-continue"] === "object") { return catnav.fn.catMembers(cat, ns, arr, data["query-continue"].categorymembers.cmcontinue, cb); } else { cb(arr); }			} else { catnav.fn.onLoadingEnd; catnav.fn.error(1, "An error has occured when looking for pages in the category " + cat + ". The error message is the following: \nError code: \nError info: " + data.error.info + " Please make sure that you've entered some text to the category input. Do not add empty lines."); }		};		req.send; };

// get members of multiple categories catnav.fn.catMembersMulti = function(catstr, ns, cb) { var cats = catstr.split("|"), completed = 0, allcats = {}; function query { if (completed == cats.length) { // all requests have been made cb(allcats); } else { catnav.fn.catMembers(cats[completed], ns, [], "", function(data) {					allcats[cats[completed]] = data;					completed++;					query;				}); }		}		query; };

// search for members that exist in all specified categories catnav.fn.joinMembers = function(data, isCommonMembers, fn) { var smallestCat, finalList = []; if (isCommonMembers === true) { // mode for the "find-in-categories" list: only list a page if it has all the listed categories smallestCat = data[catnav.fn.getSmallestCat(data)]; // start from smallest category - should take less time for (var i in smallestCat) { var itemLeSmall = smallestCat[i], // current item for check isSharedCommon = true; // if 'isCommonMembers == true', only list pages that are listed in all categories // otherwise, list all pages anyway for (var cat in data) { if (cat != smallestCat && data[cat].indexOf(itemLeSmall) == -1) { // the page 'itemLeSmall' is not categorized in one of these cats isSharedCommon = false; break; }				}				if (isSharedCommon) { finalList.push(itemLeSmall); }			}		} else { // mode for the "unwanted categories" list: list any categorized page that is categorized at least once for (var cat in data) { for (var i in data[cat]) { var currCat = data[cat][i]; if (finalList.indexOf(finalList) == -1) { // although we categorize all pages, we still don't want a category to repeat- it's time consuming and pointless finalList.push(currCat); }				}			}		}		fn(finalList); };

// find the category with the fewest members catnav.fn.getSmallestCat = function(data) { console.log("smallest cat!", data); var small = { cat: null, length: Infinity };		for (var cat in data) { if (data[cat].length < small.length) { small.cat = cat; small.length = data[cat].length; }		}		return small.cat; // return name of property with the smallest number of items };

// divide to pages - take a long list of titles, and split them to groups, each with no more than 'n' titles catnav.fn.divideToPages = function(titles) { var result = []; while (titles.length > 0) { result.push(titles.splice(0, catnav.settings.itemsInNavigator * catnav.fn.getNumberOfRows)); }		return result; };

// get number of rows catnav.fn.getNumberOfRows = function { var rows = catnav.settings.rows, specified = $("#catnav-rows").val; if ($.isNumeric(specified) && specified > 0 && specified == Math.round(specified)) { // specified number of rows is a valid positive integer rows = specified; }		return rows; };

/* functions for getting info about pages */

// implement new members catnav.fn.implementNewTitles = function(titles, categories) { // needs 'categories' parameter if advanced category sorting is desired // 'titles' is an array of page titles catnav.fn.sortTitles(titles, categories, $('[name="catnav-sort"]:checked').val, $('#catnav-dir').prop("checked"), function(sortedTitles) {			var asPages = catnav.fn.divideToPages(sortedTitles); // divide the 'titles' array to a list of smaller groups of titles			if (asPages.length > 0) {				catnav.data.current = asPages;				catnav.fn.onLoadingEnd;				catnav.fn.error(0, null); // hide error				catnav.fn.updatePagesListNav;				catnav.fn.gotoPage(0, true);				$("#catnav-resultscounter").text(function { var n = 0, c = catnav.data.current, i; for (i = 0; i < c.length; i++) { n += c[i].length; }					return n + " results found"; });			} else {				catnav.fn.onLoadingEnd;				catnav.fn.error(1, "No pages with all specified categories were found!"); // show error			}		}); };

// update pages' numbers catnav.fn.updatePagesListNav = function { var a,			pagenav = $("#catnav-pagenav"); $(pagenav).html(""); for (var i = 0; i < catnav.data.current.length; i++) { a = $('<a data-catnav-page="' + i + '" />').html("(" + (Number(i) + 1) + ")"); $(pagenav).append(a); $(a).click(function {				catnav.fn.gotoPage(Number($(this).attr("data-catnav-page")));			}); }	};

// go to page 'n + 1' catnav.fn.gotoPage = function(n, uponGeneration) { catnav.data.selectedPage = n;		$("#catnav-pagenav .catnav-pagenav-selected").removeClass("catnav-pagenav-selected"); $("#catnav-pagenav a").eq(n).addClass("catnav-pagenav-selected"); catnav.fn.queryPages(catnav.data.current[n], function(titles) {			catnav.fn.updateMarkup(titles);			// trigger events			var pageloadEvent = new Event("catnavpageload");			if (uponGeneration) {				document.querySelector("#catnav").dispatchEvent(new Event("catnavgenerated"));				pageloadEvent.uponGeneration = true;			}			document.querySelector("#catnav").dispatchEvent(pageloadEvent);		}); };

// get info about pages (url, thumb, etc.) catnav.fn.queryPages = function(titles, cb) { var req = new XMLHttpRequest, missingTitles = []; for (var i in titles) { // missingTitles lists all articles that haven't been previously loaded by 'queryPages' // articles already in 'catnav.data.details' will not be requested again if (!catnav.data.details.hasOwnProperty(titles[i])) { missingTitles.push(titles[i]); }		}		req.open("get", "/api/v1/Articles/Details?&abstract=0&width=140&height=140&titles=" + encodeURIComponent(missingTitles.join(",")), true); req.onload = function { catnav.fn.parsePagesQuery(JSON.parse(this.responseText)); cb(titles); };		if (missingTitles.length > 0) { // data about at least 1 page needs to be requested req.send; } else { // info about those pages has already loaded cb(titles); }	};

// process info about pages from json catnav.fn.parsePagesQuery = function(data) { for (var pageid in data.items) { var a = data.items[pageid], title = decodeURIComponent(a.url.substr(6)).replace(/_/g, " "); // a.title doesn't provide the namespace - easiest method is to do this catnav.data.details[title] = { id: a.id, title: title, url: a.url, img: a.thumbnail, lastedit: a.revision.timestamp, comments: a.comments };		}	};

// update markup catnav.fn.updateMarkup = function(titles) { var container = $(' '); for (var i in titles) { var a = catnav.data.details[titles[i]], item = $('<div class="catnav-item' + (a.img ? "" : " catnav-item-noimage") + '"><a href="' + a.url + '" title="' + a.title.replace(/["'&<>]/g, function(m) {return "&#" + m.charCodeAt(0) + ";";}) + '"><img src="' + (a.img ? a.img : mw.config.get("wgBlankImgUrl")) + '" width="140" height="140" /> </a> ');			$(item).find("span").text(a.title);			$(container).append(item);		}		$("#catnav-container").html($(container).html);		//window.q = container; // lol why do i always use window.q, i keep finding old lines with this whenever i set it somewhere else in the code for debugging	};

// error message catnav.fn.error = function(bool, msg) { // if 'bool' show message, otherwise hide // 'msg' is the new html content $("#catnav-noneerror").html(msg)[bool ? "show" : "hide"]; };

// collaps text catnav.fn.collapseText = function(s) { return s.replace(/\n+[ \t]+\n+|\n{2,}/g, "\n").trim; };

// sort pages by user preferences catnav.fn.sortTitles = function(titles, categories, mode, reverse, cb) { //window.q = [titles.concat, mode, reverse]; /*			modes: {					creation => by creation time lastedit => by last edit time alphabet => by alphabetic order }			'reverse' is a boolean: set as true in order to reverse the list of pages in the end of the process 'categories' parameter may be needed for specific advanced sorting methods */		mode = ["bypageid", /*"creation",*/ "lastedit", "alphabet", "populars", "comments" /*, "talksize"*/].indexOf(mode) > -1 ? mode : "alphabet"; var sortedTitles; console.log("sortTitles", arguments); switch (mode) { // @ mode == "alphabet" case "alphabet": // sort by alphabet order sortedTitles = titles.sort; if (reverse) { sortedTitles.reverse; }				cb(sortedTitles); break; // @ mode == "lastedit" or "comments" case "lastedit": case "comments": // sort by lastedit, or number of comments catnav.fn.queryPages(titles, function(titles) {					// 'catnav.fn.queryPages' is required to know how to sort all titles before splitting into navpages					var details = catnav.data.details,						title,						curr,						arr = [], // array of values (last edit timestamp or number of comments)						pagesBySortingMethod = {}, // object: key => sorting method value (timestamp or comment, value => array with titles with that associated value (in case 2+ articles have the value) i; // copy data from 'catnav.data.details' about the wanted titles for (title in details) { if (titles.indexOf(title) > -1) { curr = details[title][mode == "lastedit" ? "lastedit" : "comments"]; if (arr.indexOf(Number(curr)) === -1) { arr.push(Number(curr)); }							pagesBySortingMethod[curr] = pagesBySortingMethod[curr] || []; pagesBySortingMethod[curr].push(title); }					}					arr.sort(function(a, b) {						// sort by numerically ascending order						return a - b;					}); sortedTitles = []; for (i = 0; i < arr.length; i++ ) { // combine the mini-arrays, from the lowest timestamp to the highest sortedTitles = sortedTitles.concat(pagesBySortingMethod[arr[i]]); }					if (reverse) { sortedTitles.reverse; }					window.q = { details: details, title: title, curr: curr, arr: arr, pagesBySortingMethod: pagesBySortingMethod, i: i,						sortedTitles: sortedTitles };					cb(sortedTitles); });				break;

// @ mode == "bypageid" case "bypageid": // sort by pageid (=wgArticleId) catnav.fn.queryPages(titles, function(titles) {					// now when 'catnav.fn.queryPages' was used, 'catnav.data.details' has been created					var pagesByIds = {},						details = catnav.data.details,						title,						i,						id,						ids = [];					// 'pagesByIds': key => pageid, value => title					console.info("details as of running: " + JSON.stringify(details));					for (title in details) {						if (titles.indexOf(title) > -1) {							id = details[title].id;							pagesByIds[id] = title;							ids.push(id);						}					}					// sort by ascending ids					ids.sort(function(a, b) { return a - b;					});					// map by the now-ordered ids					sortedTitles = [];					for (i = 0; i < ids.length; i++) {						sortedTitles.push(pagesByIds[ids[i]]);					}					if (reverse) {						sortedTitles.reverse;					}					cb(sortedTitles);				}); break;

// @ mode == "populars" case "populars": // sort by most popular (using category exhibition api) catnav.fn.getCategorySizes(categories, {}, function(allcats) {					var cat,						smallestCat;					for (cat in allcats) {						allcats[cat] = new Array(allcats[cat]);					}					smallestCat = catnav.fn.getSmallestCat(allcats);					catnav.fn.getExhibitionMembers(smallestCat, [], 1, function(exMembers) { var sortedTitles = []; // final result // go through 'getExhibitionMembers' results, and add the current exhibition member // to 'sortedTitles' if the 'titles' argument (in 'sortTitles') contains it						exMembers.forEach(function(member) {							if (titles.indexOf(member) > -1) {								// member exists in the passed titles list								sortedTitles.push(member);							}						}); cb(sortedTitles); });				});				break; }	};

// get creation time of pages catnav.fn.getCreationTime = function(titles, cb) { // lol don't use this stupid module, while running it i figured it would be much more efficient to use wgArticleId :P if (titles.length === 0) { cb; } else { var req = new XMLHttpRequest; req.open("GET", mw.config.get("wgScriptPath") + "/api.php?action=query&format=json&prop=revisions&rvprop=timestamp&rvlimit=1&rvdir=newer&titles=" + encodeURIComponent(titles.shift), true); // can only get 1 title at a time when getting the first revisions :(			req.onload = function {				var data = JSON.parse(req.responseText),					pageid,					page;				for (pageid in data.query.pages) {					page = data.query.pages[pageid];					catnav.data.details[page.title] = catnav.data.details[page.title] || {};					catnav.data.details[page.title].creation = page.revisions[0].timestamp;					// continue getting data about the remaining titles					catnav.fn.getCreationTime(titles, cb);				}			};			req.send;		}	};

// manipulate storage catnav.fn.storage = function(method, savingData) { switch (method) { case "get": var storage = localStorage.getItem("catnav"); console.log(method, storage); storage = storage ? JSON.parse(storage) : {favorites: []}; console.log(method, storage); return storage; break; case "set": localStorage.setItem("catnav", JSON.stringify(savingData)); return true; break; }	};

// add favorite to list catnav.fn.insertFavorite = function(category) { var item = $(' ') .data({name: category}) .text(category) .prepend('<img src="http://www.famfamfam.com/lab/icons/silk/icons/delete.png" class="catnav-commoncats-item-delete" />', ' '); $(item).contextmenu(function(e) {			if ($(e.target).is(this)) {				e.preventDefault;				var a = $("#catnav-textarea-exclude"),					b = $(a).val.split("\n");				b.push($(this).data("name"));				$(a).val(b.join("\n").trim);			}		}).click(function(e) {			console.log(e.target, this);			if ($(e.target).is(this) && e.which === 1) {				var a = $("#catnav-textarea-include"),					b = $(a).val.split("\n");				b.push($(this).data("name"));				$(a).val(b.join("\n").trim);			}		}); $(item).find("img").click(function {			var storage = catnav.fn.storage("get"),				fave = storage.favorites,				index = fave.indexOf($(this).parent.data("name"));				if (index > -1) {					fave.splice(index, 1);					storage = catnav.fn.storage("set", storage);					$(this).parent.remove;				}		}); $("#catnav-commoncats-container").append(item); };

// import global settings (w:Special:MyPage/catnav.css) catnav.fn.addGlobalFavorites = function { var user = encodeURIComponent(mw.config.get("wgUserName")); $.ajax({			url: catnav.data.storage.url + mw.config.get("wgScriptPath") + "/api.php?action=query&format=json&prop=revisions&rvprop=content&titles=User:" + user + "/catnav.css&callback=catnavcb&" + new Date.getTime,			action: "GET",			dataType: "jsonp",			jsonpCallback: "catnavcb",			success: function(data) {				var pages = data.query.pages,					pageid,					content,					cities = {},					currCity,					wiki = location.hostname.replace(/\.wikia\.com$/i, ""),					storage;				for (pageid in pages) {					if (pageid == -1) {						alert("No data found. Please make sure that 'http://community/wiki/User:" + user + "/catnav.css' exists");					} else {						content = pages[pageid].revisions[0]["*"];						content.split("\n").forEach(function(line, lineNumber) { console.warn(lineNumber, lineNumber + 1, line); var temp; switch (line.charAt(0)) { case "@": temp = line.substr(1).trim.toLowerCase; try { currCity = temp; cities[temp] = cities[temp] || []; } catch(err) { alert("Invalid wiki subdomain at line " + (lineNumber + 1) + ": " + temp); }									break; case "#": temp = line.substr(1).trim; temp = temp.charAt(0).toUpperCase + temp.substr(1); // make first letter uppercase per case-insensitivity in pages' initials if (currCity) { cities[currCity].push(temp); } else { alert("Error at line " + (lineNumber + 1) + ": category listed without first declaring a wiki subdomain"); }									break; }						});					}					break;				}				if (cities.hasOwnProperty(wiki)) {					storage = catnav.fn.storage("get");					console.info(storage);					cities[wiki].forEach(function(category) { console.info(category); if (storage.favorites.indexOf(category) === -1) { storage.favorites.push(category); catnav.fn.insertFavorite(category); }					});					storage = catnav.fn.storage("set", storage);				}			}		}); };

// get wikia's standard categoryexhibition members of a given category catnav.fn.getExhibitionMembers = function(category, arr, page, cb) { // arguments => "Foo", [], 1, function {} var req = new XMLHttpRequest; req.open("GET", "/index.php?action=ajax&articleId=" + encodeURIComponent(category) + "&method=axGetArticlesPage&rs=CategoryExhibitionAjax&page=" + page + "&cb=" + new Date.getTime, true); req.onload = function { if (req.status == 200) { var data = JSON.parse(req.responseText), lastPage = $(data.paginator).find(".paginator-page").last.attr("data-page"); // last page is 1, if there are no subpages for the standard exhibition lastPage = $.isNumeric(lastPage) ? Number(lastPage) : 1; // add titles $(data.page).find(".title").each(function {					arr.push($(this).text);				}); // check if reached to the last page if (page === lastPage) { // last page - call 'cb' and pass the title list to its arguments cb(arr); } else { // not last page - continue to next one catnav.fn.getExhibitionMembers(category, arr, page + 1, cb); }			} else { catnav.fn.onLoadingEnd; catnav.fn.error(true, "CategoryExhibitionAjax request error (status " + req.status + "): could not load sorting resources for the list of pages. Please make sure that the wiki on which you are right now has Category Exhibition enabled. You may try some of the different sorting methods if you wish."); }		};		req.send; };

// get sizes of categories catnav.fn.getCategorySizes = function(categories, sizelist, cb) { // arguments => ["Foo1", "Foo2", "Fooetc."], {}, function {} console.log("inite :: getCategorySizes"); var req = new XMLHttpRequest, curr = categories.splice(0, 50); for (var i = 0; i < curr.length; i++) { curr[i] = "Category:" + curr[i]; }		req.open("GET", mw.config.get("wgScriptPath") + "/api.php?action=query&format=json&prop=categoryinfo&titles=" + encodeURIComponent(curr.join("|")) + "&cb=" + new Date.getTime, true); req.onload = function { var data = JSON.parse(req.responseText), cat, catname; for (var pageid in data.query.pages) { cat = data.query.pages[pageid]; catname = cat.title.replace(/^[^\:]+\:/, ""); if (!cat.hasOwnProperty("categoryinfo")) { // no category members - continue // note: pageid can be negative if the category is being used in pages, but its category page has yet to be created sizelist[catname] = 0; // note that this will be smaller than any other category!!! continue; }				sizelist[catname] = cat.categoryinfo.size; // size = any page (including other categories) that uses this category }			if (categories.length > 0) { // not done catnav.fn.getCategorySizes(categories, sizelist, cb); } else { // done cb(sizelist); }		};		req.send; };

// when no further resources are to be loaded // when all required resources have loaded and processed, or when an error prevents the process completion catnav.fn.onLoadingEnd = function { $("#catnav-loading").hide; };

// convert local favorites to global favorites syntax (that the user can copy and paste in their global list) catnav.fn.exportGlobalFavorites = function { var wiki = location.hostname.replace(/\.wikia\.com$/i, ""), favorites = catnav.fn.storage("get").favorites, lines = ["@" + wiki]; for (var i = 0; i < favorites.length; i++) { lines.push("#" + favorites[i]); }		return lines.join("\n"); };

// init catnav.fn.init = function { // # html // interface markup $("#mw-content-text").html(catnav.data.markup.html);

// # triggers // 'generate' button $("#catnav-go").click(function {			$("#catnav-loading").show; // show loading text			var incCats = catnav.fn.collapseText($("#catnav #catnav-textarea-include").val).replace(/\n/g, "|"), // included categories				disCats = catnav.fn.collapseText($("#catnav #catnav-textarea-exclude").val).replace(/\n/g, "|"), // exclude categories				catList = incCats.split("|"), // array of included categories - needed for advanced page sorting methods				nsStr = $("#catnav-ns")[0].checked ? "0" : "";			// get included categories (object: key => categoryname, val => array of listed pages in that category)			catnav.fn.catMembersMulti(incCats, nsStr, function(incData) { // sort the pages into a single array catnav.fn.joinMembers(incData, true, function(incTitles) {					if (disCats.length === 0) {						// no unwated categories requested - update immediately						catnav.fn.implementNewTitles(incTitles, catList);					} else {						// unwated categories requiested - get their categorized pages						catnav.fn.catMembersMulti(disCats, nsStr, function(disData) { // sort the pages into a single array catnav.fn.joinMembers(disData, false, function(disTitles) {								for (var i in disTitles) {									if (incTitles.indexOf(disTitles[i]) > -1) {										// unwanted page detected - remove from 'incTitles'										incTitles.splice(incTitles.indexOf(disTitles[i]), 1);									}								}								catnav.fn.implementNewTitles(incTitles, catList);							}); });					}				});			});		});		// adding categories to favorites $("#catnav-commoncats-add").click(function {			var category = prompt("Please insert a name of a category you'd like to add to favorites"),				storage;			if (category) {				storage = catnav.fn.storage("get");				if (storage.favorites.indexOf(category) === -1) {					storage.favorites.push(category);					storage = catnav.fn.storage("set", storage);					catnav.fn.insertFavorite(category);				}			}		}); // importing global categories $("#catnav-commoncats-global-import").click(function {			catnav.fn.addGlobalFavorites;		}); // initiating favorites $(function {			var storage = catnav.fn.storage("get"),				fave = storage.favorites,				i;			for (i = 0; i < fave.length; i++) {				catnav.fn.insertFavorite(fave[i]);			}		}); // export global categories $("#catnav-commoncats-global-export").click(function {			$("#catnav-export-modal-textarea").val(catnav.fn.exportGlobalFavorites);			$("#catnav-export-modal").css("display", "flex");			$("#catnav-export-modal-textarea").select;		}); // close favorites export modal $("#catnav-export-modal-close").click(function {			$("#catnav-export-modal").hide;		}); $("#catnav-export-modal").keydown(function(e) {			if (e.which == 27) {				$("#catnav-export-modal").hide;			}		}); $("#catnav-export-modal-textarea").keydown(function(e) {			if (e.which == 67 && e.ctrlKey && this.selectionEnd - this.selectionStart === this.value.length) {				// ctrl+c, while all text is selected				// close modal after 80ms (to prevent deselection of target text before copying is done)				setTimeout(function { $("#catnav-export-modal").hide; }, 80);			}		});		// mark as ready document.body.dispatchEvent(new Event("catnavready")); }

// set contrast color catnav.fn.contrastfy = function(hex) { var color = hex.replace(/[^a-f0-9]/gi, "").match(/[a-f0-9]{2}/gi), rgb = color.map(function(val) {				return parseInt(val, 16);			}), avg = (rgb[0] + rgb[1] + rgb[2]) / 3, contrast = 128 + avg - (avg < 128 ? 0 : 255); contrast = contrast.toString(16); contrast = contrast.length == 2 ? contrast : "0" + contrast; return new Array(4).join(contrast); }

/* ================================== *\		# implementations \* ================================== */

// check if the page is Special:CatNav if (mw.config.get("wgNamespaceNumber") === -1 && mw.config.get("wgTitle") == "CatNav") { /* css */ mw.util.addCSS(catnav.data.markup.css); // redefine results counter mw.util.addCSS(			'#catnav-resultscounter {\n' +				'\tcolor: ' + catnav.fn.contrastfy(wgSassParams["color-page"]) + ';\n' +			'}'		); /* markup */ // export modal (main content loaded using 'catnav.fn.init'		$("body").append( '<nav id="catnav-export-modal">\n' + '\t<nav id="catnav-export-modal-content">\n' + '\t\t \n' + '\t\t\tExport favorites\n' + '\t\t\t \n' + '\t\t \n' + '\t\t \n' + '\t\t\tCopy the following data and paste it in the bottom of your <a href="http://community.wikia.com/wiki/Special:MyPage/catnav.css">global settings</a>. \n' + '\t\t\tIn case you have previously created global favorites list for the current wiki, you might want to merge the two lists.\n' + '\t\t \n' + '\t\t<textarea id="catnav-export-modal-textarea"> \n' + '\t '+ ' '		);		// update titles		$("head title, #WikiaPageHeader h1, h1#firstHeading").html("CatNav");

// init catnav.fn.init;

// provide global access CatNav.init = catnav.fn.init; } else { // this is not Special:CatNav CatNav.init = function { console.warn("catnav :: 'CatNav.init' was requested, but has not been defined on Special:CatNav"); }	} }); //