MediaWiki:Gadget-CategoryJumpTo.js
Appearance
Note: You may have to bypass your browser’s cache to see the changes. In addition, after saving a sitewide CSS file such as MediaWiki:Common.css, it will take 5-10 minutes before the changes take effect, even if you clear your cache.
- Mozilla / Firefox / Safari: hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (Command-R on a Macintosh);
- Konqueror and Chrome: click Reload or press F5;
- Opera: clear the cache in Tools → Preferences;
- Internet Explorer: hold Ctrl while clicking Refresh, or press Ctrl-F5.
- This gadget script lacks a documentation subpage. Please create it.
- This script is a part of the
CategoryJumpTo
gadget (edit definitions)- Description (edit): Adds an input box to term category pages to jump into a specific point of the entry list.
- Useful links: subpage list • links • redirects • transclusions
// <nowiki>
/* jshint maxerr:1048576, strict:true, undef:true, latedef:true, esversion:6 */
/* global $, mw, OO */
/**
* Adds a jump box to category pages.
*
* Author(s): Surjection
* Last updated: 2024-12-19
*/
const mwApi = new mw.Api({ ajax: { headers: { "Api-User-Agent": "CategoryJumpTo gadget by [[User:Surjection]]" } } });
const strings = {
"en": {
wiktLangCode: "en",
jumpToPage: "Jump to page",
jump: "Jump",
jumpError: "There was an error while jumping. If this reoccurs, please report it on $1.",
greasePit: "the Grease Pit",
}
};
const NS_PROJECT = 4;
const GREASE_PIT_NAME = "Grease pit";
const userLanguage = mw.config.get("wgUserLanguage");
const REQUIRE_TOC = false;
const REQUIRE_CATEGORY_PAGING = true;
const resolveString = (strings, stringKey, defaultValue) => {
try {
if (defaultValue == null && stringKey)
defaultValue = stringKey;
if (strings == null)
return defaultValue;
// try to use user language first
if (strings[userLanguage] != null) {
if (stringKey == null)
return strings[userLanguage];
else if (strings[userLanguage][stringKey] != null)
return strings[userLanguage][stringKey];
}
// fall back to en
if (strings.en != null) {
if (stringKey == null)
return strings.en;
else if (strings.en[stringKey] != null)
return strings.en[stringKey];
}
return defaultValue;
} catch (_) {
// invalid strings object, etc.
return defaultValue;
}
};
const createSearchBox = (jumpCallback) => {
const outerDiv = $('<div>');
outerDiv.attr("style", "display: inline-block; margin-top: 0.5em; border: solid 1px var(--border-color-base, gray); border-collapse: collapse;");
const table = $('<table>');
outerDiv.append(table);
const body = $('<div class="center"></div>');
table.append(body.wrap('<td></td>').parent().wrap('<tr></tr>').parent().wrap('<tbody></tbody>').parent());
const MAX_LENGTH = 256;
const textInput = new OO.ui.TextInputWidget({ value: "", maxLength: MAX_LENGTH });
const jumpButton = new OO.ui.ButtonWidget({ label: resolveString(strings, "jumpToPage", "Jump to page") });
const submit = () => {
textInput.setDisabled(true);
jumpCallback(textInput.getValue().slice(0, MAX_LENGTH)).finally(() => {
textInput.setDisabled(false);
});
};
textInput.on("enter", () => submit());
jumpButton.on("click", () => submit());
const fieldset = new OO.ui.FieldsetLayout({
items: [
new OO.ui.ActionFieldLayout(textInput, jumpButton)
]
});
body.append(fieldset.$element);
return outerDiv;
};
const htmlUnescape = (text) => new DOMParser().parseFromString(text, "text/html").body.textContent;
const getSortKey = (languageCode, text) =>
new Promise((resolve, reject) => {
const escapedText = text.replace(/[\x00-\x1F\x21-\x2F\x3A-\x40\x5B-\x60\x7B-\x7F]/g, (m) => `&#${m.charCodeAt(0)};`);
const wikitext = `{{sortkey|${languageCode}|${escapedText}}}`;
const params = {
action: "expandtemplates",
format: "json",
prop: "wikitext",
text: wikitext
};
mwApi.post(params).then(response => {
resolve(htmlUnescape(response.expandtemplates.wikitext));
}).catch((e) => {
reject(e);
});
});
const addJumpBox = () => {
const catfix = $(".catfix");
if (!catfix.length) return;
let languageCode = catfix.find("span[lang]");
if (!languageCode.length) return;
languageCode = languageCode.attr("lang");
// do not display if there are no pages
if (!$("#mw-pages").length) return;
const toc = $("#toc");
if (REQUIRE_TOC && !toc.length) return;
if (REQUIRE_CATEGORY_PAGING && !$('#mw-pages a[href*="pagefrom="], #mw-pages a[href*="pageuntil="]').length) return;
const searchBox = createSearchBox((string) =>
new Promise((resolve, reject) => {
getSortKey(languageCode, string).then((sortKey) => {
const url = new URL(window.location.href);
url.searchParams.delete("pagefrom");
url.searchParams.set("from", sortKey);
resolve();
window.location.href = url.href;
}).catch(() => {
const greasePitUrl = new mw.Title(GREASE_PIT_NAME, NS_PROJECT).getUrl();
const greasePitLink = $("<a>").attr("href", greasePitUrl).text(resolveString(strings, "greasePit"));
const errorMessage = $("<span>").text(resolveString(strings, "jumpError"));
errorMessage.html(errorMessage.html().replace('\$1', greasePitLink[0].outerHTML));
mw.notification.notify(errorMessage, { "type": "error" });
reject();
});
})
);
const target = toc.length ? toc : catfix;
searchBox.wrap("<div>").parent().insertBefore(target.first());
};
addJumpBox();
// </nowiki>