Jump to content

User:Epicgenius/sortcategories.js: Difference between revisions

From Wikipedia, the free encyclopedia
Content deleted Content added
fix
modify
Line 74: Line 74:
var preText = wpTextbox1_V.substr(0, categoriesStart);
var preText = wpTextbox1_V.substr(0, categoriesStart);
var trimmedPreText = preText.replace(/\s+$/, "");
var trimmedPreText = preText.replace(/\s+$/, "");
⚫
var lastNewLineIndex = trimmedPreText.lastIndexOf("\n");


// Use no newline before categories if DEFAULTSORT exists;
var lastLine =
// otherwise, use exactly one newline.
lastNewLineIndex !== -1
⚫
var separator = wpTextbox1_V.indexOf(defaultSort) >= 0
⚫
? trimmedPreText.substr(lastNewLineIndex + 1)
: trimmedPreText;
? ""
⚫
: "\n";

// Determine separator based on whether the line immediately
// above starts with a {{DEFAULTSORT}} template.
⚫
var separator = "\n\n";

if (lastLine.trim().indexOf(defaultSort) === 0) {
⚫
separator = "\n";
⚫
}


var textWithCategories = wpTextbox1_V
var textWithCategories = wpTextbox1_V
Line 173: Line 165:
textWithCategories = splitCategories.join("\n");
textWithCategories = splitCategories.join("\n");


// If a stub template occurs before the first category,
⚫
if (wpTextbox1_V.indexOf(defaultSort) < 0) {
// ensure exactly one newline separates it from the category.
textWithCategories = "\n" + textWithCategories;
⚫
var lastStubIndex = trimmedPreText.lastIndexOf(stubTag);
⚫
}


if (wpTextbox1_V.indexOf(stubTag) >= 0) {
if (lastStubIndex >= 0) {
textWithCategories =
var textThroughLastStub =
⚫
trimmedPreText.substr(
textWithCategories + "\n\n";
0,
lastStubIndex + stubTag.length
⚫
);

var textAfterLastStub =
trimmedPreText.substr(
lastStubIndex + stubTag.length
);

if (/^\s*$/.test(textAfterLastStub)) {
trimmedPreText = textThroughLastStub;
⚫
separator = "\n";
⚫
}
}
}



Revision as of 17:31, 9 October 2026

/* 
See [[User:Alex 21/script-categoriessort.js]], original script by [[User:Alex 21]]

The main script page is [[User:Epicgenius/sortcategories.js]].
*/
// <nowiki>
mw.loader.using("mediawiki.util", function () {
	// Only run script if user is editing an article
	if (
		!document.forms.editform ||
		(mw.config.get("wgAction") !== "edit" &&
			mw.config.get("wgAction") !== "submit")
	) {
		return;
	}

	$(function ($) {
		mw.loader.using(["mediawiki.util"]).then(function () {
			var portletlink = mw.util.addPortletLink(
				"p-tb",
				"#",
				"Sort categories"
			);

			$(portletlink).click(function (e) {
				e.preventDefault();

				var wpTextbox1 = document.getElementById("wpTextbox1");
				var $wpTextbox1 = $("#wpTextbox1");

				if (!wpTextbox1 || !$wpTextbox1.length) {
					return;
				}

				// CodeMirror support, or an attempt at such
				var activeElement = document.activeElement;
				var inCodeMirror =
					activeElement &&
					activeElement.tagName === "DIV" &&
					$(activeElement).hasClass("cm-content");

				var wpTextbox1_V;

				if (inCodeMirror) {
					// Get the actual contents from CodeMirror.
					wpTextbox1_V = $wpTextbox1.textSelection("getContents");
				} else {
					// Normal textarea.
					wpTextbox1_V = wpTextbox1.value;
				}

				// Categories to check
				var category = "[[Category:";
				var categoryA = category + "A ";
				var categoryAn = category + "An ";
				var categoryThe = category + "The ";
				var categoryEnd = "]]";
				var categoryEponymous =
					category + mw.config.get("wgTitle");
				var defaultSort = "{{DEFAULTSORT:";
				var stubTag = "-stub}}";

				// Get the text up to the start of the categories,
				// and then all of the text with the categories.
				var categoriesStart = wpTextbox1_V.indexOf(category);
				var categoriesEnd = wpTextbox1_V.lastIndexOf(categoryEnd);

				// No categories found.
				if (categoriesStart === -1 || categoriesEnd === -1) {
					mw.notify("No categories found", { type: "info" });
					return;
				}

				var preText = wpTextbox1_V.substr(0, categoriesStart);
				var trimmedPreText = preText.replace(/\s+$/, "");

				// Use no newline before categories if DEFAULTSORT exists;
				// otherwise, use exactly one newline.
				var separator = wpTextbox1_V.indexOf(defaultSort) >= 0
					? ""
					: "\n";

				var textWithCategories = wpTextbox1_V
					.substr(
						categoriesStart,
						categoriesEnd - categoriesStart + 2
					)
					.trim();

				var textAfterCategories = wpTextbox1_V
					.substr(categoriesEnd + 2)
					.trim();

				/*
				 * Categories should be on new lines, so split by new line,
				 * sort alphabetically with a few checks, then join again.
				 *
				 * Checks:
				 * - eponymous categories are listed first
				 * - categories are sorted without preceding "The", "A",
				 *   or "An"
				 */
				var splitCategories = textWithCategories.split("\n");

				splitCategories.sort(function (a, b) {
					if (
						a.substr(0, categoryEponymous.length) ===
						categoryEponymous
					) {
						return -1e8;
					}

					if (
						b.substr(0, categoryEponymous.length) ===
						categoryEponymous
					) {
						return 1e8;
					}

					if (
						a.substr(0, categoryThe.length) ===
						categoryThe
					) {
						a = a.replace(categoryThe, category);
					}

					if (
						b.substr(0, categoryThe.length) ===
						categoryThe
					) {
						b = b.replace(categoryThe, category);
					}

					if (
						a.substr(0, categoryA.length) ===
						categoryA
					) {
						a = a.replace(categoryA, category);
					}

					if (
						b.substr(0, categoryA.length) ===
						categoryA
					) {
						b = b.replace(categoryA, category);
					}

					if (
						a.substr(0, categoryAn.length) ===
						categoryAn
					) {
						a = a.replace(categoryAn, category);
					}

					if (
						b.substr(0, categoryAn.length) ===
						categoryAn
					) {
						b = b.replace(categoryAn, category);
					}

					return a.localeCompare(b);
				});

				textWithCategories = splitCategories.join("\n");

				// If a stub template occurs before the first category,
				// ensure exactly one newline separates it from the category.
				var lastStubIndex = trimmedPreText.lastIndexOf(stubTag);

				if (lastStubIndex >= 0) {
					var textThroughLastStub =
						trimmedPreText.substr(
							0,
							lastStubIndex + stubTag.length
						);

					var textAfterLastStub =
						trimmedPreText.substr(
							lastStubIndex + stubTag.length
						);

					if (/^\s*$/.test(textAfterLastStub)) {
						trimmedPreText = textThroughLastStub;
						separator = "\n";
					}
				}

				// Ensure any text after the final category is split
				// onto its own line.
				if (textAfterCategories !== "") {
					textAfterCategories =
						"\n" + textAfterCategories;
				}

				// Merge pre-category text back with the sorted category text.
				var newContent =
					trimmedPreText +
					separator +
					textWithCategories +
					textAfterCategories;

				// Write the result back.
				if (inCodeMirror) {
					$wpTextbox1.textSelection(
						"setContents",
						newContent
					);
				} else {
					wpTextbox1.value = newContent;
				}

				setoptions(minor = "true");
				setreason(
					"sorted categories alphabetically via [[User:Epicgenius/sortcategories|script]]",
					"append"
				);
				doaction("diff");
			});
		});
	});
});
// </nowiki>