MediaWiki:Gadget-nearby.js
(Redirected from User:Dixtosa/nearby.js)
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 script lacks a documentation subpage. Please create it.
- This script is a part of the
nearby
gadget (edit definitions)- Description (edit): Add links to "nearby" entries at the top of each language section, similar to other online dictionaries.
- Useful links: subpage list • links • redirects
// Do a preliminary check to avoid running the gadget unnecessarily.
if ([0, 100, 118].includes(mw.config.values.wgNamespaceNumber) && Array.from(document.querySelectorAll("#catlinks li")).some(cat => cat.textContent.endsWith(" lemmas"))) {
let actionAPI = new mw.Api({ ajax: { headers: { "Api-User-Agent": "Gadget developed by [[User:Ioaxxere]]" } } });
let pageName = mw.config.values.wgPageName;
const N_ENTRIES = 3; // the number of preview entries on each side of the current page
// Given a page title (no underscores), return the prettified title.
function makeDisplayTitle(rawTitle) {
rawTitle = rawTitle.replaceAll("_", " ");
if (rawTitle.startsWith("Reconstruction:"))
return "*" + rawTitle.split("/").pop();
if (rawTitle.startsWith("Appendix:"))
return rawTitle.split("/").pop();
if (rawTitle.startsWith("Unsupported titles/"))
return convertUnsupportedTitle(rawTitle); // from [[MediaWiki:Gadget-UnsupportedTitles.js]]
return rawTitle;
}
let pageCategorySortkeys = new Map();
// This function recursively builds pageCategorySortkeys, which is a map from each page category to its associated sortkey.
function categoryQueries(continueParam) {
let params = {
action: "query",
format: "json",
cllimit: "max",
clprop: "sortkey",
prop: "categories",
titles: pageName
};
if (continueParam)
params.clcontinue = continueParam;
return actionAPI.get(params).then(response => {
for (let category of response.query.pages[Object.keys(response.query.pages)[0]].categories) {
pageCategorySortkeys.set(category.title, category.sortkeyprefix);
}
if (response.continue)
return categoryQueries(response.continue.clcontinue);
});
}
categoryQueries().then(() => {
for (let h2 of document.querySelectorAll(".mw-heading2 h2")) {
let language = h2.id.replaceAll("_", " ");
let category = "Category:" + language + " lemmas";
if (!pageCategorySortkeys.has(category)) continue; // skip non-lemmas and malformed entries
let params = {
action: "query",
cmlimit: 40, // arbitrary; we don't know how many we need ahead of time
format: "json",
list: "categorymembers",
cmsort: "sortkey",
cmtitle: category,
cmstartsortkeyprefix: pageCategorySortkeys.get(category)
};
actionAPI.get(params).then(response => {
// Filter out category members from namespace 14 (Category:)
let titles = response.query.categorymembers.filter(page => page.ns !== 14).map(page => page.title);
// pageName is guaranteed to be in this list unless there are over `cmlimit` pages with the same sortkey.
let currPagePosition = titles.indexOf(pageName.replaceAll("_", " "));
let entriesAhead = titles.slice(currPagePosition + 1, currPagePosition + N_ENTRIES + 1);
let entriesBehind = titles.slice(Math.max(currPagePosition - N_ENTRIES, 0), currPagePosition);
let secondQuery = Promise.resolve();
if (entriesBehind.length < N_ENTRIES) {
// If entriesBehind isn't yet long enough, switch direction and get the entries coming before.
// There are no duplicates between the first and second queries.
params.cmdir = "desc";
secondQuery = secondQuery.then(() => actionAPI.get(params));
}
secondQuery.then(secondResponse => {
if (secondResponse) {
let secondTitles = secondResponse.query.categorymembers.filter(page => page.ns !== 14).map(page => page.title);
entriesBehind = secondTitles.slice(0, N_ENTRIES - entriesBehind.length).reverse().concat(entriesBehind);
}
// Display nearby entries on the page.
let nearbyEntriesDiv = document.createElement("div");
nearbyEntriesDiv.className = "nearby-entries-box";
nearbyEntriesDiv.style = "padding: 6px; margin-top: 10px; background: var(--wikt-palette-palergreen, #f8fffa); width: fit-content; max-width: 100%; border: 1.5px solid var(--wikt-palette-forestgreen, #235923); border-radius: 2px; overflow-wrap: break-word";
nearbyEntriesDiv.innerText = "» ";
// Need to account for both HTML formats.
if (h2.parentElement.nextElementSibling.tagName === "SECTION")
h2.parentElement.nextElementSibling.prepend(nearbyEntriesDiv);
else
h2.parentElement.parentElement.insertBefore(nearbyEntriesDiv, h2.parentElement.nextElementSibling);
for (entry of entriesBehind) {
let entryLink = document.createElement("a");
entryLink.href = "/wiki/" + mw.util.wikiUrlencode(entry) + "#" + h2.id;
entryLink.title = entry;
entryLink.textContent = makeDisplayTitle(entry);
nearbyEntriesDiv.append(entryLink, " • ");
}
let selflink = document.createElement("a");
selflink.className = "mw-selflink selflink";
selflink.textContent = makeDisplayTitle(pageName);
nearbyEntriesDiv.append(selflink);
for (entry of entriesAhead) {
let entryLink = document.createElement("a");
entryLink.href = "/wiki/" + mw.util.wikiUrlencode(entry) + "#" + h2.id;
entryLink.title = entry;
entryLink.textContent = makeDisplayTitle(entry);
nearbyEntriesDiv.append(" • ", entryLink);
}
});
})
}
});
}