MediaWiki:Gadget-catfixRegrouper.js
Jump to navigation
Jump to search
Note: After publishing, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
- Opera: Press Ctrl-F5.
// {{documentation}}
// <nowiki>
// implicit dependencies : mediawiki.Title, ext.gadget.catfixRegrouper-Data
/* jshint maxerr:1048576, strict:true, undef:true, latedef:true, esversion:6 */
/* global $, mw, RegrouperMetadata */
/* data is in [[MediaWiki:Gadget-catfixRegrouper-Data.js]] */
// characters to ignore when looking for the initial in a title.
// this is embedded inside a RegExp character class
const REGROUPER_INITIALS = "-";
function safeUpperCase(text, dottedDotlessI) {
if (dottedDotlessI)
return text.replace(/i/g, "İ").toUpperCase();
else
return text.toUpperCase();
}
function safeLowerCase(text, dottedDotlessI) {
if (dottedDotlessI)
return text.replace(/I/g, "ı").toLowerCase();
else
return text.toLowerCase();
}
function titleCase(text, lang, sc) {
return safeUpperCase(text.charAt(0), this.dottedDotlessI)
+ safeLowerCase(text.substring(1), this.dottedDotlessI);
}
function defaultGroup(title, lang, sc) {
if (title.length < 1) return undefined;
const cleaned = title.replace(this._clean_regex, "");
if (this.initials) {
const initialMatch = cleaned.match(this._initials_regex);
if (initialMatch) {
return titleCase(initialMatch[0], lang, sc);
}
if (!this.initialFallback) return undefined;
}
title = cleaned || title;
return titleCase(title.charAt(0), lang, sc);
}
function makeGroup(groupText) {
const groupDiv = document.createElement("div");
groupDiv.className = "mw-category-group";
const groupH3 = document.createElement("h3");
groupH3.textContent = groupText;
groupDiv.append(groupH3);
const groupUl = document.createElement("ul");
groupDiv.append(groupUl);
return [groupDiv, groupUl];
}
function getLiText(el) {
const child = $(el).find("a, span").first();
const rawText = el.textContent || el.innerText;
return (child.length > 0 && child.text()) || rawText;
}
jQuery(() => {
'use strict';
let catfix;
// Apply only to pages in the Category namespace
// containing an element with the id "catfix".
// Set window.disableCatfixRegrouper to true to prevent this script from running.
if (!(!window.disableCatfixRegrouper
&& mw.config.get('wgNamespaceNumber') === 14
&& (catfix = $(".catfix")).length))
return;
catfix = catfix[0];
const catfixSpan = catfix.querySelector("span");
if (!catfixSpan) return;
const regrouperMeta = new RegrouperMetadata();
// Get the language name and script catfix.
const langName = decodeURIComponent(catfix.getAttribute("data-anchor").replace(/_/g, " "));
catfix = catfix.getElementsByTagName("*")[0] || document.createElement("span");
const lang = catfixSpan.getAttribute("lang");
const defaultSc = catfixSpan.classList[0] || "None";
const cachedScriptData = {};
if (!lang)
return;
const UNPREFIXED_NAMESPACES = ["", "Talk", "Citations"];
const PREFIXED_NAMESPACES = ["Appendix", "Appendix talk", "Reconstruction", "Reconstruction talk"];
function isEntry(namespaceName, pageName) {
// main, Talk, Citations,
// Reconstruction/Appendix (Talk) if it starts with language name and "/"
return UNPREFIXED_NAMESPACES.indexOf(namespaceName) !== -1
|| (PREFIXED_NAMESPACES.indexOf(namespaceName) !== -1
&& pageName.slice(0, langName.length + 1) === langName + "/");
}
const formattedNamespaces = mw.config.get("wgFormattedNamespaces");
const regrouperData = regrouperMeta.getByLang(lang);
if (!regrouperData) return;
// set up stuff for the default regrouper
regrouperData._clean_regex = new RegExp("^[" + ((regrouperData.ignoreAdd || "") + (regrouperData.ignore || REGROUPER_INITIALS)) + "]+");
if (regrouperData.initials)
regrouperData._initials_regex = new RegExp("^" + regrouperData.initials.source, regrouperData.initials.flags);
const groupFunction = regrouperData.group;
const detectScriptFunction = regrouperData.detectScript;
function getGroup(pageTitle, oldGroup) {
const titleobj = new mw.Title(pageTitle);
const namespaceId = titleobj.getNamespaceId();
const namespaceName = formattedNamespaces[namespaceId];
const pageName = titleobj.getMainText();
if (!isEntry(namespaceName, pageName))
return oldGroup;
// verify language prefix if the namespace should have one
let formattedTitle = pageName;
const langPrefix = langName + "/";
if (PREFIXED_NAMESPACES.indexOf(namespaceName) !== -1) {
if (formattedTitle.startsWith(langPrefix)) {
formattedTitle = formattedTitle.substring(langPrefix.length);
} else {
return oldGroup;
}
}
// ignore unsupported titles unless the language data requests otherwise
if (formattedTitle.startsWith("Unsupported titles/") && !regrouperData.unsupported)
return oldGroup;
// script detection
let sc = defaultSc;
if (detectScriptFunction)
sc = detectScriptFunction.call(regrouperData, formattedTitle, lang, sc, namespaceId) || sc;
let scData = cachedScriptData[sc];
if (!scData)
scData = cachedScriptData[sc] = regrouperMeta.getBySc(sc) || {};
let newGroup = true;
// the language group function may return true to fall back
if (groupFunction)
newGroup = groupFunction.call(regrouperData, formattedTitle, lang, sc, namespaceId);
if (newGroup === true && scData.group)
newGroup = scData.group.call(regrouperData, formattedTitle, lang, sc, namespaceId);
if (newGroup === true)
newGroup = defaultGroup.call(regrouperData, formattedTitle, lang, sc, namespaceId);
return newGroup || oldGroup;
}
const GROUP_QUERY = "#mw-pages > .mw-content-ltr .mw-category-group";
let regroupOk = true;
const regroupData = new Map();
// Process each group in the category listing.
jQuery(GROUP_QUERY)
.each(function () {
// Get the existing group.
const group = $(this).find("h3").first().text();
if (!group) {
// Failed to get group -- something has gone wrong.
regroupOk = false;
return;
}
$(this).find("li")
.each(function () {
try {
const liText = getLiText(this);
const newGroup = getGroup(liText, group);
regroupData.set(liText, newGroup);
} catch (e) {
console.error(e);
regroupOk = false;
}
});
});
// Find the existing groups, which we will delete.
const groups = jQuery(GROUP_QUERY);
// Cannot regroup if there are no groups.
if (!groups.length) return;
const parent = groups.first().parent()[0];
if (!parent) return;
const fragment = document.createDocumentFragment();
if (regroupOk) {
let lastGroup, groupUl;
jQuery(GROUP_QUERY + " li")
.each(function () {
const liText = getLiText(this);
const newGroup = regroupData.get(liText) || "";
if (lastGroup !== newGroup) {
const elements = makeGroup(newGroup);
const groupDiv = elements[0];
fragment.appendChild(groupDiv);
groupUl = elements[1];
lastGroup = newGroup;
}
groupUl.appendChild(this);
});
groups.remove();
parent.appendChild(fragment);
}
});
// </nowiki>