MediaWiki:Gadget-AutoGlossary.js
Eslatma: Saqlaganingizdan soʻng, oʻzgarishlarni koʻrish uchun brauzeringiz keshini tozalashingizga toʻgri kelishi mumkin.
- Firefox / Safari: Shift tugmasini bosgan holda, Yangilash unsurlar darchasini bosing, yoki Ctrl-F5 yoki Ctrl-R (Macda ⌘-R) ni bosing
- Google Chrome: Ctrl-Shift-R (Macda ⌘-Shift-R) ni bosing
- Internet Explorer / Edge: Ctrlni bosgan holda, Yangilashni bosing, yoki Ctrl-F5ni bosing
- Opera: Ctrl-F5ni bosing.
// Polyfill for async/await, adapted from tsc __awaiter.
// Takes in a generator function that yields promises.
// The function recursively consumes the generator until all promises are completed.
const asAsync = generator => new Promise(resolve => {
function step(result) {
if (result.done)
resolve(result.value);
else
Promise.resolve(result.value).then(v => step(iteration.next(v)));
}
let iteration = generator();
step(iteration.next());
});
mw.util.addCSS(`
.mw-parser-output .auto-glossary a[rel~="mw:ExtLink"]:empty::after {
content: '[' counter(mw-numbered-ext-link) ']';
counter-increment: mw-numbered-ext-link;
}
.mw-parser-output .auto-glossary td:first-child {
counter-reset: mw-numbered-ext-link;
text-align: center;
}
.mw-parser-output .auto-glossary ol {
margin: 0 0 0 2em;
padding: 0;
}
`);
asAsync(function* () {
for (let autoGlossary of document.querySelectorAll(".auto-glossary")) {
let category = autoGlossary.getAttribute("data-category");
let label = autoGlossary.getAttribute("data-label"); // The label parameter is currently unused.
let lang = autoGlossary.getAttribute("data-language");
let inlineOnly = autoGlossary.getAttribute("data-inline-only");
let actionAPI = new mw.Api({ ajax: { headers: { "Api-User-Agent": "Gadget developed by [[User:Ioaxxere]]" } } });
let restAPI = new mw.Rest({ ajax: { headers: { "Api-User-Agent": "Gadget developed by [[User:Ioaxxere]]" } } });
let wordlist = [];
let continueParam;
// Get a list of words in the given category.
while (true) {
let response = yield actionAPI.get({
action: "query",
list: "categorymembers",
cmprop: "title",
cmlimit: "max",
cmtitle: "Category:" + category,
cmcontinue: continueParam
});
// Only include entries from mainspace, appendix space, and reconstruction space.
for (let entry of response.query.categorymembers) {
if (entry.ns === 0 || entry.ns === 100 || entry.ns === 118)
wordlist.push(entry.title);
}
if (!response.continue)
break;
continueParam = response.continue.cmcontinue;
}
wordlist.sort((a, b) => (/^[A-Za-z]/.test(a) ? /^[A-Za-z]/.test(b) ? a.localeCompare(b, undefined, { sensitivity: "base" }) : -1 : /^[A-Za-z]/.test(b) ? 1 : 0)); // ChatGPTsort
let entriesLoaded = 0;
let loadingIndicator = document.createElement("div");
autoGlossary.append(loadingIndicator);
let glossaryTable = document.createElement("table");
glossaryTable.className = "wikitable";
glossaryTable.style = "width: 100%; table-layout: fixed; display: table";
glossaryTable.innerHTML = `<thead><tr><th style="width:8em">Terms</th><th>Definitions</th></tr></thead><tbody></tbody>`;
let batchSize = 500;
for (let batchStart = 0; batchStart < wordlist.length; batchStart += batchSize) {
if (batchStart === batchSize)
batchSize = 10e99; // Finish the rest of the list.
let ongoingRequests = 0;
let glossaryRows = yield Promise.all(wordlist.slice(batchStart, batchStart + batchSize).map(word => asAsync(function* () {
// Limit concurrent requests, otherwise the browser might run of out memory.
while (ongoingRequests >= 200)
yield new Promise(resolve => setTimeout(resolve, 10));
ongoingRequests++;
let response = yield restAPI.get("/v1/page/" + encodeURIComponent(word) + "/html");
ongoingRequests--;
let responseDocument = new DOMParser().parseFromString(response, "text/html");
let row;
try {
let langID = lang.replace(/ /g, "_");
let L2_section = responseDocument.getElementById(langID).parentNode;
let glossaryDefs = Array.from(L2_section.getElementsByTagName("li")).filter(li => {
// Check if the li element contains an inline category.
if (Array.from(li.querySelectorAll(":scope > link[rel=\"mw:PageProp/Category\"], :scope > span > span > link[rel=\"mw:PageProp/Category\"]"))
.some(linkElement => linkElement.getAttribute("href").startsWith("./Category:" + category.replace(/ /g, "_")))) {
return true;
}
// Check if the headword element contains the category.
let headwordLine = li.parentElement.previousElementSibling;
if (!inlineOnly && headwordLine && headwordLine.tagName === "P" &&
Array.from(headwordLine.querySelectorAll("link[rel=\"mw:PageProp/Category\"]"))
.some(linkElement => linkElement.getAttribute("href").startsWith("./Category:" + category.replace(/ /g, "_")))) {
return true;
}
return false;
});
// If no definitions found: grab all top-level definitions.
if (!inlineOnly && !glossaryDefs.length)
glossaryDefs = L2_section.querySelectorAll(".mw-parser-output section > ol > li");
// Insert a row if definitions were found.
if (glossaryDefs.length) {
let entryLink = document.createElement("a");
entryLink.href = "https://en.wiktionary.org" + mw.util.getUrl(word) + "#" + langID;
entryLink.textContent = word;
let defList = document.createElement("ol");
defList.append(...glossaryDefs);
// Convert URLs into absolute URLs.
for (let link of defList.querySelectorAll("a[href]"))
link.href = new URL(link.getAttribute("href"), "https://en.wiktionary.org" + mw.util.getUrl(word)).href;
// Clean HTML.
defList.querySelectorAll("link, .previewonly, .maintenance-line").forEach(elem => elem.remove());
for (let elem of defList.querySelectorAll("*")) {
Array.from(elem.attributes).forEach(attr => {
if (attr.name !== "class" && attr.name !== "href" && attr.name !== "style" && attr.name !== "title" && attr.name !== "rel") {
elem.removeAttribute(attr.name);
}
});
}
row = document.createElement("tr");
row.insertCell(0).append(entryLink);
row.insertCell(1).append(defList);
}
} catch (e) {
console.log("auto-glossary.js could not parse: " + word);
}
entriesLoaded++;
loadingIndicator.textContent = `Loaded entry: ${entriesLoaded}/${wordlist.length}`;
return row;
})));
if (batchStart === 0)
autoGlossary.append(glossaryTable);
for (let row of glossaryRows.filter(Boolean)) {
for (let quote of document.querySelectorAll("ol > li"))
window.setupHiddenQuotes(quote);
glossaryTable.querySelector("tbody").append(row);
}
}
// Clear out loading display.
Array.from(autoGlossary.childNodes).forEach(elem => {
if (elem !== glossaryTable)
elem.remove();
});
}
});