User:Danski454/stubsearch.js

// //from a request by Insertcleverphrasehere //based on User:Ais523/stubtagtab2.js, which is in turn based on User:MC10/stubtagtab.js

//variables var SSunfilteredArray = ["stub"];//does not contain parent var stubTags = {"stub":{display:"", parents:["stubs"], children:null, descendants:null, template:"Stub"},"stubs":{display:"Stubs", parents:null, children:[], descendants:["stub"], template:null}};//generic stub is not loaded by the normal method var SSfilteredArray = ["stub"]; var stublists = ['Architecture', 'Commerce', 'Culture', 'Education', 'Geography', 'Government, law, and politics', 'History', 'Leisure', 'Military and weaponry', 'Organizations', 'People', 'Religion, mythology, faiths, and beliefs', 'Science', 'Sports', 'Technology', 'Transport', 'Miscellaneous']; var stubTemplates = [""];

var SSactive = false;

var SScurrent = stubTags["stubs"]; var SSoldid = null; var SSnewid = null; var SSpagesLoaded = 0; var SSextraChildren = [{parent:"education stubs", children:["school stubs", "university stubs"]}, {parent:"company stubs", children:["Aeronautical company stubs", "Airline stubs", "Animation studio stubs", "Brand name products stubs", "Chemical company stubs", "Disney stubs", "Energy company stubs", "Fashion company stubs", "Film company stubs", "Financial services company stubs", "Food company stubs", "Hotel stubs", "Industrial company stubs", "Information technology company stubs", "Leisure company stubs", "Manufacturing company stubs", "Media company stubs", "Motor vehicle company stubs", "Music industry company stubs", "Musical instrument company stubs", "Petroleum company stubs", "Publishing company stubs", "Restaurant stubs", "Retail company stubs", "Service company stub", "Technological company stubs", "Telecommunications company stubs", "Toy company stubs", "Transport company stubs", "Video game company stubs", "African company stubs", "Asian company stubs", "European company stubs", "Canadian company stubs", "Mexican company stubs", "United States company stubs", "Australian company stubs", "South American company stubs"]}, {parent:"politics stubs", children:["Asia politics stubs", "Europe politics stubs", "Canada politics stubs", "United States politics stubs", "Mexican politics stubs", "New Zealand politics stubs", "South America politics stubs", "Political party stubs", "Political people stubs", "Politician stubs"]}, {parent:"politician stubs", children:["African politician stubs", "Asian politician stubs", "European politician stubs", "North American politician stubs", "Oceanian politician stubs", "South American politician stubs"]}, {parent:"history stubs", children:["American Old West stubs", "Ancient Near East stubs", "Ancient Egypt stubs", "Ancient Greece stubs", "Ancient Rome stubs", "Byzantine Empire stubs", "Kingdom of France stubs", "Mesoamerica stubs", "Nazi Germany stubs", "Netherlands Antilles stubs", "Ottoman Empire stubs", "Pre-Columbian era stubs", "Soviet Union stubs", "Yugoslavia stubs", "African diaspora stubs", "East Slavic history stubs", "Jewish history stubs", "African history stubs", "Asian history stubs", "European history stubs", "Canadian history stubs", "Mexican history stubs", "United States history stubs", "South American history stubs", "Military history stubs"]}, {parent:"people stubs", children:["Academic biography stubs", "Artist stubs", "Astronaut stubs", "Business biography stubs", "Entertainer stubs", "Explorer stubs", "Fashion biography stubs", "Graphic designer stubs", "Journalist stubs", "Medical biography stubs", "Model stubs", "Paramilitary biography stubs", "Piracy stubs", "Religious biography stubs", "Scientist stubs", "Writer stubs", "African people stubs", "Asian people stubs", "European people stubs", "North American people stubs", "Caribbean people stubs", "Central American people stubs", "Oceanian people stubs", "South American people stubs", "Nobility stubs", "Royalty stubs"]}, {parent:"scientist stubs", children:["Asian scientist stubs", "African scientist stubs", "Australian scientist stubs", "European scientist stubs", "North American scientist stubs", "South American scientist stubs"]}, {parent:"science stubs", children:["scientist stubs", "Biology stubs", "Botany stubs", "Animal stubs", "Astronomy stubs", "Chemistry stubs", "Atmospheric science stubs", "Geology stubs", "Oceanography stubs", "Physics stubs", "Health stubs", "Anthropology stubs", "Library and information science stubs", "Sociology stubs", "Natural science stubs"]}, {parent:"chordate stubs", children:["Amphibian stubs", "Bird stubs", "Fish stubs", "Mammal stubs", "Reptile stubs"]}, //Amphibians, Birds, Fish, Mammals, and Reptiles {parent:"protostome stubs", children:["Mollusc stubs"]}, {parent:"arthropod stubs", children:["insect stubs", "Arachnid stubs"]}, {parent:"technology stubs", children:["Computing stubs", "Software stubs", "Telecommunications stubs", "Automotive part stubs", "Automotive technology stubs", "Electronics stubs", "Energy stubs", "Engineering stubs", "Industry stubs", "Metalworking stubs", "Robotics stubs", "Sound technology stubs", "Tool stubs", "Woodworking stubs"]}, {parent:"transport stubs", children:["Africa transport stubs", "Asia transport stubs", "Europe transport stubs", "North America transportation stubs", "Oceania transport stubs", "South America transport stubs", "Space stubs", "Vehicle stubs", "Water transport stubs", "Aviation stubs", "Rail transport stubs", "Road stubs"]}, {parent:"military stubs", children:["African military stubs", "Argentine military stubs", "Asian military stubs", "Australian military stubs", "Canadian military stubs", "European military stubs", "Mexican military stubs", "United States military stubs", "Military personnel stubs"]}, {parent:"organization stubs", children:["Trade union stubs", "Art organization stubs", "Automotive organization stubs", "Business organization stubs", "Criminal organization stubs", "Education organization stubs", "Environmental organization stubs", "Film organization stubs", "Fraternity and sorority stubs", "Freemasonry stubs", "International organization stubs", "Lesbian, gay, bisexual, transgender (LGBT) organization stubs", "Linguistics organization stubs", "Medical organization stubs", "Music organization stubs", "Non-profit organization stubs", "Paramilitary organization stubs", "Political organisation stubs", "Professional association stubs", "Religious organization stubs", "Scientific organization stubs", "Youth organization stubs", "African organization stubs", "Asian organization stubs", "Australian organisation stubs", "Canadian organization stubs", "European organisation stubs", "Mexican organization stubs", "New Zealand organisation stubs", "South American organization stubs", "United States organization stubs"]}];

//functions function SSloadDiff{ window.location.href = mw.config.get('wgScript') + '?diff=' + SSnewid + '&oldid=' + SSoldid; }

function SSreduceArray(unreducedArray){ var seen = {}; return unreducedArray.filter(function(item) {       return seen.hasOwnProperty(item) ? false : (seen[item] = true);    }); }

function SSescape(text, html){ if (html){ return text .replace('"', "&quot;")			.replace("&", "&amp;")			.replace("'", "&#039;")			.replace("<", "&lt;")			.replace(">", "&gt;");	} else {		return text			.replace('"', "\\x22") .replace("&", "\\x26") .replace("'", "\\x27") .replace("<", "\\x3c") .replace(">", "\\x3e"); } }

function SSgenerateDescendants(start){ if (stubTags[start].descendants !== null && stubTags[start].descendants.length !== 0){//already generated descendants return stubTags[start].descendants.concat([start]); }	if (stubTags[start].children === null || stubTags[start].children.length === 0){//no descendants return [start];//for the rest, we are the only descendant }	stubTags[start].children.forEach( function (value, index, array) {		stubTags[start].descendants = stubTags[start].descendants.concat(SSgenerateDescendants(value));//add children's descendants to our own	}); stubTags[start].descendants = SSreduceArray(stubTags[start].descendants);//remove duplicates return stubTags[start].descendants.concat([start]); }

function SSaddchild(parent, child){ if (stubTags.hasOwnProperty(parent)){//check parent exists if (stubTags[parent].template !== null){//check if parent is a template, if so call this on its parents stubTags[parent].parents.forEach(function (value, index, array) { SSaddchild(value, child); }); return; }		//check if parent already has child if (stubTags[parent].children.indexOf(child) !== -1){ return; }		stubTags[parent].children.push(child);//add child to parents children } else {//create a parent stubTags[parent] = {display:parent, parents:[], children:[child], descendants:[], template:null}; stubTags.stubs.descendants.push(parent);//add to stubs' descendants }	if (stubTags.hasOwnProperty(child)){//check if child exists stubTags[child].parents.push(parent);//add parent to child } else {//create child stubTags[child] = {display:child, parents:[parent], children:[], descendants:[], template:null}; stubTags.stubs.descendants.push(child);//add to stubs' descendants } }

function SSconvertToTemplate(parent, template){ if (stubTags[parent].children === null){//already a template return; }	stubTags[parent].template = template;//set up template and display stubTags[parent].display = ''; stubTemplates.push(('')); stubTags[parent].children.forEach( function (value, index, array) {//remove all children's parent reference		index = stubTags[value].parents.indexOf(parent);//don't need index		if (index > -1) {			stubTags[value].parents.splice(index, 1);		}		SSaddchild(parent, value);//try to readd this as a child of parent	}); stubTags[parent].children = null;//clear the array }

function SSdoExtraChildren{ $.each(SSextraChildren, function { //do children in array		var parent = this.parent;		this.children.forEach(function (value, index, array){ SSaddchild(parent, value.toLowerCase); });	});	addStubType("Unlisted stubs", "cat", "stubs");//special case for unlisted stubs }

function stubFilter{ filterString = document.getElementById("stub-search-search").value; //Special case: no filterString then only show direct children if (filterString.length === 0){ SSfilteredArray = SScurrent.children; SSrerenderList; return; }	var filteringArray = SSunfilteredArray; //copy unfiltered array filterString = filterString.toLowerCase; //force lowercase var filterArray = filterString.split(" "); //split string for (var filterIndex = 0; filterIndex < filterArray.length; filterIndex++) { SSfilteredArray = [];//clear the filtered output filterString = filterArray[filterIndex]; for (var i = 0; i < filteringArray.length; i++) { var testString = filteringArray[i]; if (testString.indexOf(filterString) > -1){ SSfilteredArray.push(testString); }		}		filteringArray = SSfilteredArray; }	SSrerenderList; }

function loadStubs{ for (var i = 0; i < stublists.length; i++) { var stubType = stublists[i]; $.ajax({			url: mw.config.get("wgServer") + mw.config.get("wgScriptPath") + '/api.php?action=parse&prop=text&text=' + encodeURIComponent('\{\{Wikipedia:WikiProject Stub sorting/Stub types/' + stubType + '}}') + '&format=json',			dataType: "json",			success: stubSearchLoadSome,			error: function { 				SSpagesLoaded++;//increment loaded pages on failure so the menu auto loads				console.log("Stub search failed to load a stub list.");			}		}); }	//special case for unlisted stubs $.ajax({		url: mw.config.get("wgServer") + mw.config.get("wgScriptPath") + '/api.php?action=parse&prop=text&text=' + encodeURIComponent('\{\{User:Danski454/unlisted stubs}}') + '&format=json',		dataType: "json",		success: stubSearchLoadSome,		error: function { 			SSpagesLoaded++;//increment loaded pages on failure so the menu auto loads			console.log("Stub search failed to load a stub list.");		}	}); SSdoExtraChildren; }

function stubSearchLoadSome(data) { var parseData = $(data.parse.text["*"]); var parent = "stubs"; if (parseData.find("h1, h2").length){ switch (parseData.find("h1, h2").first.text.toLowerCase){ case "sports": parent = "sports stubs"; break; case "culture": parent = "culture stubs"; break; case "contents": parent = "architecture stubs"; break; }	} else if (parseData.find("h3").length === 0) {//special case for unlisted stubs parent = "unlisted stubs"; }	parseData.children("ul").children('li').each( function {		var val = $(this);//'this' must be converted to jQuery		while (val.find("small").length !== 0) {//remove small tags (copied from toggleSmall.js)			var tag = val.find("small").first;			tag.before(tag.html);			tag.remove;		}		$('dl').remove;//remove description lists		generateStubData(val, parent);	}); if (parent !== "stubs" && parent !== "unlisted stubs"){ stubTags[parent].children.shift;//remove from its own children stubTags[parent].parents = [];//remove from its own parents SSaddchild("stubs", parent);//make a child of stubs }	SSpagesLoaded++; if (SSpagesLoaded == stublists.length + 1){//one list is not listed in the array stubFilter; } }

function addStubType(obj, type, parent){ var name = obj.toLowerCase; SSaddchild(parent, name);//this creates the object if (type === "template"){ SSconvertToTemplate(name, obj); } else { stubTags[name].display = obj;//set display name }	SSunfilteredArray.push(name); SSfilteredArray.push(name); }

function generateStubData(data, parent){ var cat; cat = data.children("b").first.text;//categories are in bold if (cat !== ""){ addStubType(cat, "cat", parent); parent = cat.toLowerCase; }	data.children("ul").children('li').each( function {			generateStubData($(this), parent);	}); data.children("a").each( function {//template links are not wrapped		var tag = $(this);		if (tag[0].previousSibling !== null && tag[0].previousSibling.nodeValue.endsWith("as a child of {{")){//get text before element and make sure it does not say x is a child of y			return true;		}		if (tag[0].previousSibling !== null && tag[0].previousSibling.nodeValue.endsWith("child of {{")){//get text before element and handle next element is child of x			var next = tag.next;//get next list item			if (next.is("ul")){//if next is a list get the first item of it				next = next.children("li").first;			}			SSaddchild(tag.text.toLowerCase, next.children('b').first.text.toLowerCase);//make next link a child of us			return true;		}		if (tag.attr("href").search(/(wiki\/|=)Template:/) === -1){//must link to a template			return true;		}		addStubType(tag.text, "template", parent);	}); }

function SSrerenderList{ $('#stub-search-scroll').empty; SSfilteredArray = SSreduceArray(SSfilteredArray); //remove duplicates SSfilteredArray.forEach(function (value, index, array) {		var tag = stubTags[value];		if (index > 0){			$('#stub-search-scroll').append("•");		}		$('#stub-search-scroll').append('');	}); }

function SSrenderTemplate{ $('#stub-search-scroll').empty; $('#stub-search-scroll').append(' Preview loading '); $.ajax({		url: mw.config.get("wgServer") + mw.config.get("wgScriptPath") + '/api.php?action=parse&prop=text&text=' + encodeURIComponent('\{\{' + SScurrent.template + '}}') + '&format=json',		dataType: "json",		success: function (data){			$('#stub-preview').before('    Load changes ');			$('#stub-preview').html($(data.parse.text["*"]));		}	}); }

function stubSearchUp{ var stub = $('#stub-search-parent-select option:selected').val; selectStub(stub); }

function loadStubSearch{ if (SSactive){ return; }	SSactive = true; switch ( mw.config.get('skin') ){ case 'cologneblue': $('#mw-content-text').before('Search:  Current selection: Stubs   Loading stub templates: Please wait '); break; case 'timeless': $('#bodyContent').before('Search:  Current selection: Stubs   Loading stub templates: Please wait '); break; default: $('#bodyContent').before('<div id="stub-search-box" style="background-color:LightBlue;height:200px;border:1px solid black;padding:15px;">Search: <input type="text" id="stub-search-search"><input id="stub-search-button" type="button" value="Search" onclick="stubFilter;" /> Current selection: Stubs <input id="stub-search-up" type="button" value="Go up to" onclick="stubSearchUp;" /><select id="stub-search-parent-select"> <input id="stub-search-diff-button" type="button" value="Load changes" onclick="SSloadDiff;" /> Loading stub templates: Please wait '); }	$('#stub-search-up, #stub-search-parent-select, #stub-search-diff-button').hide;//up button, drop down and load diff button default to hidden loadStubs; }

function selectStub(name){ SSgenerateDescendants(name);//generate the descendants, if they have not already been. SScurrent = stubTags[name]; $('#stub-search-cat').text(SScurrent.display); document.getElementById("stub-search-search").value = "";//clear search $('#stub-search-parent-select').empty;//clear old parents selector if (SScurrent.parents !== null){ $('#stub-search-up, #stub-search-parent-select').show;//show parent selector and button if (SScurrent.parents[0] === "unlisted stubs") {//special case $('#stub-search-parent-select').append('<option value="'+ SSescape("stubs", true) +'">'+ SSescape(stubTags["stubs"].display, true) +' ') }		SScurrent.parents.forEach(function (value, index, array){			$('#stub-search-parent-select').append('<option value="'+ SSescape(value, true) +'">'+ SSescape(stubTags[value].display, true) +' ')		}); } else { $('#stub-search-up, #stub-search-parent-select').hide;//hide parent selector and button }	if (SScurrent.template === null){ SSunfilteredArray = SScurrent.descendants; stubFilter; } else { SSrenderTemplate; } }

function addStub{ replaceStub(true);//functions merged }

function replaceStub(keepOld){//adds a stub template, optionally keeping old ones, this is copied from WP:US/G $.getJSON(		mw.util.wikiScript('api'),		{			format: 'json',			action: 'query',			prop: 'revisions',			rvprop: 'content',			rvlimit: 1,			titles: mw.config.get( 'wgPageName' )		}	) .done(function ( data ) {			var page, wikitext;			try {				for ( page in data.query.pages ) {					wikitext = data.query.pages[page].revisions[0]['*'];					replaceStubWikitext( wikitext, keepOld );				}			} catch ( e ) {				console.log(1);				alert( 'Edit failed' );			}		}) .fail( function {			console.log(2);			alert( 'Edit failed' );		}); }

function replaceStubWikitext(data, keepOld){ added_text = '\n\n\n{{'+ SScurrent.template +'}}'; stubTemplates.forEach(function (value, index, array){		var re = new RegExp(value, "gi");		if (keepOld && data.match(re) !== null){			added_text = added_text + '\n' + value;//readd stub template to bottom		}		data = data.replace(re, "");//replace stubs with nothing using unescaped regex	}); data = data.replace(/\s+$/g, "");//remove trailing whitepace, do not use m flag data = data + added_text; console.log(data); var summary = 'Replaced stub templates with {{'+ SScurrent.template +'}} using a tool'; if (keepOld){ summary = 'Added {{'+ SScurrent.template +'}} using a tool'; }	//save data $.ajax({		url: mw.util.wikiScript( 'api' ),		type: 'POST',		dataType: 'json',		data: {			format: 'json',			action: 'edit',			title: mw.config.get( 'wgPageName' ),			text: data, 			summary: summary,			token: mw.user.tokens.get( 'csrfToken' )		}	}) .done (function( data ) {		if ( data && data.edit && data.edit.result && data.edit.result == 'Success') {			if (SSoldid === null){				if (data.edit.oldrevid !== undefined){					SSoldid = data.edit.oldrevid;				} else {					alert("Unable to determine oldid");				}			}			if ($('#stub-search-load-diff').is(':checked') && data.edit.newrevid !== undefined){				if (SSoldid !== null && data.edit.oldrevid !== undefined){					window.location.href = mw.config.get('wgScript') + '?diff=' + data.edit.newrevid + '&oldid=' + SSoldid;//load diff				} else {					alert("Unable to load diff");				}			} else {				if (keepOld){					alert( 'Successfully added {{'+ SScurrent.template +'}} to the article' );				} else {					alert( 'Successfully replaced stubs with {{'+ SScurrent.template +'}}' );				}				if (data.edit.newrevid !== undefined){					SSnewid = data.edit.newrevid;				} else {					alert("Unable to determine newid"); }				if (SSoldid !== null && SSnewid !== null && $('#stub-search-diff-button').is(':hidden')){ $('#stub-search-diff-button').show;//add a load diff button if we have not loaded the diff }				selectStub('stubs');//reset the UI, user probably wans to add another template }		} else { console.log(3); alert( 'Edit failed' ); }	})	.fail ( function { console.log(4); alert( 'Edit failed' ); }); }

$(document).ready(function{	if ( mw.config.get( 'wgNamespaceNumber' ) === 0 || mw.config.get( 'wgPageName' ) === "Wikipedia:Sandbox" ) {//usable on articles and the sandbox (for testing and practice)		var portletLink = mw.util.addPortletLink('p-cactions', '#', 'Stub search', 'ca-stub-search', 'Tag this article as a stub', '');		$(portletLink).click(loadStubSearch);	} }); //