Jump to content

User:Danski454/stubsearch.js

From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by Danski454 (talk | contribs) at 17:35, 25 October 2018 (made bugfixes). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
//from a request by Insertcleverphrasehere
//based on [[User:Ais523/stubtagtab2.js]], which is in turn based on [[User:MC10/stubtagtab.js]]

//variables
var unfilteredArray = ["stub"];//does not contain parent
var stubTags = {"stub":{display:"Stub", 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 filteredArray = ["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 current = stubTags["stubs"];
var pagesLoaded = 0;

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

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].dispaly = '{{'+ template +'}}';
	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 stubFilter(){
	filterString = document.getElementById("stub-search-search").value;
	//Special case: no filterString then only show direct children
	if (filterString.length === 0){
		filteredArray = current.children;
		SSrerenderList();
		return;
	}
	
	var filteringArray = unfilteredArray; //copy unfiltered array
	filterString = filterString.toLowerCase(); //force lowercase
	var filterArray = filterString.split(" "); //split string
	
	for (var filterIndex = 0; filterIndex < filterArray.length; filterIndex++) {
		filteredArray = [];//clear the filtered output
		filterString = filterArray[filterIndex];
		for (var i = 0; i < filteringArray.length; i++) {
			var testString = filteringArray[i];
			if (testString.indexOf(filterString) > -1){
				filteredArray.push(testString);
			}
		}
		filteringArray = filteredArray;
	}
	SSrerenderList();
}

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

function stubSearchLoadSome(data) {
	var parseData = $(data.parse.text["*"]);
	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();
		}
		generateStubData(val, "stubs");//children of the generic stub
	});
	pagesLoaded++;
	if (pagesLoaded == stublists.length){
		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
	}
	unfilteredArray.push(name);
	filteredArray.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();
	filteredArray = SSreduceArray(filteredArray); //remove duplicates
	filteredArray.forEach(function (value, index, array) {
		var tag = stubTags[value];
		if (index > 0){
			$('#stub-search-scroll').append("•");
		}
		$('#stub-search-scroll').append('<input type="button" value="'+ tag.display +'" onclick="selectStub(\''+ value +'\');" style="background:none!important;color:inherit;border:none;cursor:pointer;" class="stub-search-type" />');
	});
}

function SSrenderTemplate(){
	$('#stub-search-scroll').empty();
	$('#stub-search-scroll').append('<input type="button" value="Add {{'+ current.template +'}} to this article" onclick="addStub();" id="stub-search-confirm" /><br /><span id="stub-preview">Preview loading</span>');
	$.ajax({
		url: mw.config.get("wgServer") + mw.config.get("wgScriptPath") + '/api.php?action=parse&prop=text&text=' + encodeURIComponent('__NOTOC____NOEDITSECTION__\{\{' + current.template + '}}') + '&format=json',
		dataType: "json",
		success: function (data){
			$('#stub-preview').html($(data.parse.text["*"]));
		}
	});
}

function stubSearchUp(){
	selectStub(current.parents[0]);
}

function loadStubSearch(){
	switch ( mw.config.get('skin') ){
		case 'cologneblue':
			$('#mw-content-text').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: <span id="stub-search-cat">Stubs</span> <input id="stub-search-up" type="button" value="Go up to ..." onclick="stubSearchUp();" /><br /><div style="max-height:175px;overflow:auto;" id="stub-search-scroll">Loading stub templates: Please wait</div></div>');
			break;
		case 'timeless':
			$('#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: <span id="stub-search-cat">Stubs</span> <input id="stub-search-up" type="button" value="Go up to ..." onclick="stubSearchUp();" /><br /><div style="max-height:150px;overflow:auto;" id="stub-search-scroll">Loading stub templates: Please wait</div></div>');
			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: <span id="stub-search-cat">Stubs</span> <input id="stub-search-up" type="button" value="Go up to ..." onclick="stubSearchUp();" /><br /><div style="max-height:175px;overflow:auto;" id="stub-search-scroll">Loading stub templates: Please wait</div></div>');
	}
	$('#stub-search-up').hide();//up button defaults to hidden
	loadStubs();
}

function selectStub(name){
	SSgenerateDescendants(name);//generate the descendants, if they have not already been.
	current = stubTags[name];
	$('#stub-search-cat').text(current.display);
	document.getElementById("stub-search-search").value = "";//clear search
	if (current.parents !== null){
		$('#stub-search-up').val("Go up to " + stubTags[current.parents[0]].display).show();//for now, show first parent
	} else {
		$('#stub-search-up').hide();
	}
	if (current.template === null){
		unfilteredArray = current.descendants;
		stubFilter();
	} else {
		SSrenderTemplate();
	}
}

function addStub(){
	$.ajax({
		url: mw.util.wikiScript( 'api' ),
		type: 'POST',
		dataType: 'json',
		data: {
			format: 'json',
			action: 'edit',
			title: mw.config.get( 'wgPageName' ),
			appendtext: '\n{{'+ current.template +'}}', // will replace entire page content
			summary: 'Added {{'+ current.template +'}} using [[User:Danski454/stubsearch|a tool]]',
			token: mw.user.tokens.get( 'editToken' )
		}
	})
	.done (function( data ) {
		if ( data && data.edit && data.edit.result && data.edit.result == 'Success' ) {
			alert( 'Successfully added {{'+ current.template +'}} to the article' );
		} else {
			alert( 'Edit failed' );
		}
	})
	.fail ( function() {
		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);
	}
});