User:Proteins/sortunorderedlists.js

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.
//<pre>
// Sorts an unordered list alphabetically
// Generally useful, but designed for Special:WhatLinksHere
// Uses specialized version of quicksort for unordered lists
// 
// To use this script, add "importScript('User:Proteins/sortunorderedlists.js');" to your monobook.js subpage 
// under your user page, as you can see at User:Proteins/monobook.js


//************************
// Swap list item function
//************************

function swapTwoListItems(arg_list_items_array, arg_list_index1, arg_list_index2) {
	var error_string = "";

	var parent_list1;
	var parent_list2;

	var next_sibling1;
	var next_sibling2;

	var arg_list_item1;
	var arg_list_item2;

	// Check for identity
	if (arg_list_index1 == arg_list_index2) { return; } 

	arg_list_item1 = arg_list_items_array[arg_list_index1];
	arg_list_item2 = arg_list_items_array[arg_list_index2];

	if ((!arg_list_item1) && (!arg_list_item2)) { 
		error_string = "ERROR: Both list items " + arg_list_index1 + " & " + arg_list_index2 + " do not exist.";
		window.alert(error_string);
		return; 
	} else if (!arg_list_item1) { 
		error_string = "ERROR: List item 1 " + arg_list_index1 + " does not exist.";
		window.alert(error_string);
		return; 
	} else if (!arg_list_item2) {
		error_string = "ERROR: List item 2 " + arg_list_index2 + " does not exist.";
		window.alert(error_string); 
		return; 
	}

	parent_list1 = arg_list_item1.parentNode;
	if (!parent_list1) {
		error_string = "ERROR: Parent node of list item 1 does not exist.";
		window.alert(error_string); 
		return; 
	} 
	if (parent_list1.nodeType != 1) { 
		error_string = "ERROR: Parent node of list item 1 is not an Element.";
		window.alert(error_string); 
		return; 
	} 
	if (parent_list1.tagName != "UL") { 
		error_string = "ERROR: Parent node of list item 1 is not a \"UL\" Element.";
		window.alert(error_string); 
		return; 
	} 

	parent_list2 = arg_list_item2.parentNode;
	if (!parent_list2) {
		error_string = "ERROR: Parent node of list item 2 does not exist.";
		window.alert(error_string); 
		return; 
	} 
	if (parent_list2.nodeType != 1) { 
		error_string = "ERROR: Parent node of list item 2 is not an Element.";
		window.alert(error_string); 
		return; 
	} 
	if (parent_list2.tagName != "UL") { 
		error_string = "ERROR: Parent node of list item 2 is not a \"UL\" Element.";
		window.alert(error_string); 
		return; 
	} 

	next_sibling1 = arg_list_item1.nextSibling;
	next_sibling2 = arg_list_item2.nextSibling;

	if ((!next_sibling1) && (!next_sibling2)) { 
		error_string = "ERROR: Next siblings of both list items are NULL.";
		window.alert(error_string); 
		return;
	} else if (!next_sibling1) {	
		parent_list1.appendChild(arg_list_item2);
		parent_list2.insertBefore(arg_list_item1, next_sibling2);
	} else if (!next_sibling2) { 
		parent_list2.appendChild(arg_list_item1);
		parent_list1.insertBefore(arg_list_item2, next_sibling1);
	} else { 
		parent_list1.insertBefore(arg_list_item2, next_sibling1);
		parent_list2.insertBefore(arg_list_item1, next_sibling2);
	}
	arg_list_items_array[arg_list_index1] = arg_list_item2;
	arg_list_items_array[arg_list_index2] = arg_list_item1;
	return;
} // closes function swapTwoListItems()


//***************************
// Compare list item function
//***************************

function compareTwoListItems(arg_list_item1, arg_list_item2) { 
	var alert_string = "";

	var inner_text1;
	var inner_text2;

	if ((!arg_list_item1) && (!arg_list_item2)) {
		alert_string = "00: Both list items are undefined.";
		window.alert(alert_string);
		return 0;
	} else if (!arg_list_item1) { 
		alert_string = "-1: List item 1 is undefined.";
		window.alert(alert_string);
		return -1;
	} else if (!arg_list_item2) { 
		alert_string = "+1: List item 2 is undefined.";
		window.alert(alert_string);
		return 1;
	}
 
	inner_text1 = arg_list_item1.innerHTML;
	inner_text2 = arg_list_item2.innerHTML;
	if ((!inner_text1) && (!inner_text2)) {
		alert_string = "00: No innerHTML in either list item.";
		window.alert(alert_string);
		return 0;
	} else if (!inner_text1) {
		alert_string = "-1: No innerHTML in list item 1.";
		window.alert(alert_string);
		return -1;
	} else if (!inner_text2) { 
		alert_string = "+1: No innerHTML in list item 2.";
		window.alert(alert_string);
		return 1;
	}

	inner_text1 = inner_text1.replace(/<[^>]+>/ig, "");
	inner_text2 = inner_text2.replace(/<[^>]+>/ig, "");

	inner_text1 = inner_text1.replace(/&gt;/ig, ">");
	inner_text2 = inner_text2.replace(/&gt;/ig, ">");

	inner_text1 = inner_text1.replace(/&lt;/ig, "<");
	inner_text2 = inner_text2.replace(/&lt;/ig, "<");

	inner_text1 = inner_text1.replace(/&amp;/ig, "&");
	inner_text2 = inner_text2.replace(/&amp;/ig, "&");

	inner_text1 = inner_text1.replace(/&nbsp;/ig, " ");
	inner_text2 = inner_text2.replace(/&nbsp;/ig, " ");

	inner_text1 = inner_text1.replace(/&#160;/ig, " ");
	inner_text2 = inner_text2.replace(/&#160;/ig, " ");

	inner_text1 = inner_text1.replace(/\s+/ig, "");
	inner_text2 = inner_text2.replace(/\s+/ig, "");

	if (inner_text1>inner_text2) { 
//		alert_string = "+1: " + inner_text1.substr(0,20) + "  " + inner_text2.substr(0,20);
//		window.alert(alert_string);
		return 1; 
	} 
	if (inner_text1<inner_text2) {
//		alert_string = "-1: " + inner_text1.substr(0,20) + "  " + inner_text2.substr(0,20);
//		window.alert(alert_string);
		return -1; 
	} 
//	alert_string = "00: " + inner_text1.substr(0,20) + "  " + inner_text2.substr(0,20);
//	window.alert(alert_string);
	return 0; 

} // closes function compareTwoListItems()


//************************
// Partition list function
//************************

function partitionAnUnorderedList(arg_list_items, first_index, last_index, pivot_index) {
	var alert_string = "";
	var error_string = "";

	var temp_list_item;
	var num_list_items = 0;
	var list_item_index = 0;
	var store_item_index = 0;

	var pivot_list_item = arg_list_items[pivot_index];

	swapTwoListItems(arg_list_items, pivot_index, last_index-1);
//	alert_string = "Swapped pivot item " + pivot_index + " to " + (last_index-1) + " position.\n";
//	window.alert(alert_string);

	store_item_index = first_index;
	for (list_item_index=first_index; list_item_index<last_index-1; list_item_index++) { 
		temp_list_item = arg_list_items[list_item_index];
		if (!temp_list_item) { 
			error_string = "ERROR: Undefined list item " + list_item_index + " in partition of " + first_index + "–" + last_index + " about pivot " + pivot_index + ".\n";
			window.alert(error_string);
		}
		if (!pivot_list_item) { 
			error_string = "ERROR: Pivot list item " + pivot_index + " in partition of " + first_index + "–" + last_index + " has become undefined.\n";
			window.alert(error_string);
		}

		if (compareTwoListItems(temp_list_item, pivot_list_item) < 0) {
 			swapTwoListItems(arg_list_items, store_item_index, list_item_index);
			store_item_index++;
		}
	}
	swapTwoListItems(arg_list_items, last_index-1, store_item_index);
	return store_item_index;
} // closes function partitionAnUnorderedList()


//******************************
// Quicksort for unordered lists
//******************************

function quicksortAnUnorderedList(arg_list_items, first_index, last_index) { 
	var alert_string = "";

	var pivot_index = 0;

	if(last_index>first_index) {
		pivot_index=(first_index+last_index)/2;
		pivot_index = Math.floor(pivot_index);
//		alert_string = "For items " + first_index + "–" + last_index + ", the pivot index is " + pivot_index + "\n";
//		window.alert(alert_string);

		pivot_index=partitionAnUnorderedList(arg_list_items, first_index, last_index, pivot_index);
//		alert_string = "Partitioned items " + first_index + "–" + last_index + " about the pivot index " + pivot_index + "\n";
//		window.alert(alert_string);

		quicksortAnUnorderedList(arg_list_items, first_index, pivot_index);
		quicksortAnUnorderedList(arg_list_items, pivot_index+1, last_index);
	}

} // closes function quicksortAnUnorderedList()


//**********************************************
// Callback function for individual list buttons
//**********************************************

function sortAnUnorderedList(arg_list) {
	var alert_string = "";
	var error_string = "";

	var child_nodes;
	var temp_child_node;
	var num_child_nodes = 0;
	var child_node_index = 0;

	var num_list_items = 0;
	var list_items = new Array();


	alert_string = "List className = " + arg_list.className + ".";
//	window.alert(alert_string);

	child_nodes = arg_list.childNodes;
	if (!child_nodes) {
		alert_string = "This list has no child nodes; there's nothing to sort!";
		window.alert(alert_string); 
		return; 
	} 
	num_child_nodes  = child_nodes.length;
	if (child_nodes<1) {
		alert_string = "This list has zero child nodes; there's nothing to sort!";
		window.alert(alert_string); 
		return; 
	} 

	num_list_items = 0;
	for (child_node_index=0; child_node_index<num_child_nodes; child_node_index++) { 
		temp_child_node = child_nodes[child_node_index]; 
		if (!temp_child_node) { continue; } 
		if (temp_child_node.nodeType != 1) { continue; } 
		if (temp_child_node.tagName != "LI") { continue; }

		num_list_items++;
		list_items.push(temp_child_node);
	} // closes loop over the child nodes

//	alert_string = "Found " + num_list_items + " list items of " + num_child_nodes + " child nodes.\n";
//	window.alert(alert_string);

	// Quicksort for efficiency; useful with 5000-item links
	quicksortAnUnorderedList(list_items, 0, num_list_items);

	alert_string = "Sorted table of " + num_list_items + " list items.";
	window.alert(alert_string);

} // closes function sortAnUnorderedList()


//******************
// The Main Function
//******************

function addSortButtonsToAllUnorderedLists() { 
	var list_string = "";
	var alert_string = "";
	var error_string = "";

	var body_content;
 
	var temp_list;
	var num_lists = 0;
	var list_index = 0;
	var unordered_lists;
	var num_sortable_lists = 0;

	var list_items;
	var temp_list_item;
	var num_list_items = 0;

	var temp_hyperlink;


// Get the bodyContent node
	body_content = document.getElementById('bodyContent');
	if (!body_content) { 
		error_string = "ERROR: There is no bodyContent node in this article.";
		window.alert(error_string);
		return;
	}


// Get unordered lists
	unordered_lists = body_content.getElementsByTagName("UL");
	if (!unordered_lists) { 
		alert_string = "This page has no unordered lists.\n\n";
		window.alert(alert_string);
		return;
	}
	num_lists = unordered_lists.length;
	if (num_lists < 1) { 
		alert_string = "This page has zero unordered lists.\n\n";
		window.alert(alert_string);
		return;
	}


// Loop over the unordered lists
	list_string = "";
	num_sortable_lists = 0; 
	for (list_index=1; list_index<=num_lists; list_index++) {
		temp_list = unordered_lists[list_index-1];
		if (!temp_list) { 
			error_string = "ERROR: Unordered list " + list_index + " is undefined.\n\n";
			window.alert(error_string);
			continue;
		}

		// Filter out unwanted lists, such as those of the Table of Contents
		list_items = temp_list.getElementsByTagName("LI");
		if (!list_items) { continue; } 

		num_list_items = list_items.length;
		if (num_list_items < 1) { continue; } 

		temp_list_item = list_items[0];
		if (!temp_list_item) { continue; } 
		if (temp_list_item.className.match(/^toclevel/)) { continue; } 

		// Calculate number of list items at the correct level 
		child_nodes = temp_list.childNodes;
		if (!child_nodes) { continue; } 

		num_child_nodes  = child_nodes.length;
		if (child_nodes<1) { continue; } 

		num_list_items = 0;
		for (child_node_index=0; child_node_index<num_child_nodes; child_node_index++) { 
			temp_child_node = child_nodes[child_node_index]; 
			if (!temp_child_node) { continue; } 
			if (temp_child_node.nodeType != 1) { continue; } 
			if (temp_child_node.tagName != "LI") { continue; }

			num_list_items++;
		} // closes loop over the child nodes
		if (num_list_items < 2) { continue; } // a list of one item doesn't need to be sorted


		// Create the sorting button and add it at the top of the list
		num_sortable_lists++; 
		list_string += "List " + num_sortable_lists + " has " + num_list_items + " list items.\n";

		temp_hyperlink = document.createElement("A");
		if (!temp_hyperlink) { 
			error_string = "ERROR: Unable to create hyperlink in unordered list " + list_index + ".\n";
			window.alert(error_string);
			continue;
		} 
		temp_hyperlink.onclick = function() { sortAnUnorderedList(this.parentNode); } 
		temp_hyperlink.appendChild(document.createTextNode("CLICK TO SORT LIST " + num_sortable_lists + " (" + num_list_items + " items)"));

		first_child = temp_list.firstChild;
		if (first_child) { 
			temp_list.insertBefore(temp_hyperlink, first_child);
		} else { 
			temp_list.appendChild(temp_hyperlink);
		}
	} // closes loop over the lists


// Print acknowledgment
	alert_string = "Added sort buttons to " + num_sortable_lists + " unordered lists.\n\n";
	alert_string += list_string;
	window.alert(alert_string);

} // closes function addSortButtonsToAllUnorderedLists()

$(function () {
mw.util.addPortletLink('p-navigation', 'javascript:addSortButtonsToAllUnorderedLists()', 'Sort lists', 'ca-sortlists', 'Sort unordered lists', '', '');
});
 
//</pre>