User:Nikki/MiscFeatures.js
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)
- Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
/**
* This script includes an assortment of small features.
*
* To use it, add the following line to your common.js:
* mw.loader.load("//www.wikidata.org/w/index.php?title=User:Nikki/MiscFeatures.js&action=raw&ctype=text/javascript");
*
* @license CC0-1.0
*/
/* jshint esnext: false, esversion: 8 */
(function () {
"use strict";
/* Add tab indexes to links which act like buttons */
function add_tab_indexes() {
$(".wikibase-toolbar-button a:not([tabindex])").each(function () {
this.tabIndex = 0;
$(this).on("click keydown", function (event) {
if (event.type === "click" || event.key == "Enter") {
setTimeout(add_tab_indexes, 500);
}
});
});
}
/* Display hex colours as a little box before the code */
function display_colours() {
let elements = [];
/* select usage as main value */
elements.concat(document.querySelectorAll("#P465 .wikibase-snakview-value"));
/* select usage as qualifier */
for (const el of document.querySelectorAll("a[title='Property:P465']")) {
const el2 = el.parentNode.parentNode.parentNode.querySelector(".wikibase-snakview-value");
elements.push(el2);
}
for (const el of elements) {
const hex = el.textContent;
mw.util.addCSS(".misc-features-colour-preview {\
display: inline-block;\
height: 1.2em;\
border: 1px solid #222;\
aspect-ratio: 1;\
margin-right: 3px;\
line-height: 1.2em\
}");
el.insertAdjacentHTML("afterbegin", "<span class='misc-features-colour-preview' style='background-color: #" + mw.html.escape(hex) + "'> </span>");
}
}
/* Improve the display of URLs by adding <wbr> around punctuation */
function better_url_display() {
for (let e of document.querySelectorAll("a.external")) {
if (e.href !== e.innerHTML) {
continue;
}
e.innerHTML = e.innerHTML.replace(/(?!<[:\/])([\/.-]+)/g, "<wbr>$1<wbr>");
}
}
/* Collapse references section, change the text colour instead */
function collapse_references() {
for (let el of document.querySelectorAll(".wikibase-statementview-references")) {
if (!el.querySelector(".wikibase-listview")) {
var a = el.parentNode.querySelector("a.ui-toggler");
a.style.color = "#c00";
a.click();
a.click();
}
}
}
function display_statement_count() {
mw.util.addCSS(".statement-count { color: #777; font-size:smaller }");
$("div.wikibase-statementgroupview.listview-item").each(function () {
var c = $(this).find(".wikibase-statementview").length;
if (c > 10) {
$(this).find(".wikibase-statementgroupview-property-label").append("<br><span class='statement-count'>(" + c + " statements)</span>");
}
});
}
/* Add links for uselang=qqx, safemode=1 and debug=1 to the top menu */
function add_debug_links() {
mw.util.addPortletLink(
"p-cactions",
mw.Uri().extend({ "uselang": "qqx" }).toString(),
"uselang=qqx",
"ca-qqx",
"Show untranslated message IDs"
);
mw.util.addPortletLink(
"p-cactions",
mw.Uri().extend({ "safemode": "1" }).toString(),
"safemode=1",
"ca-safemode",
"Enable safe mode (no gadgets or user CSS/JS)"
);
mw.util.addPortletLink(
"p-cactions",
mw.Uri().extend({ "debug": "1" }).toString(),
"debug=1",
"ca-debug",
"Enable debug mode (No minification of CSS/JS files)"
);
}
/* Expand the termbox on load if it's collapsed */
function expand_termbox() {
$(".wikibase-entitytermsview-entitytermsforlanguagelistview-toggler.ui-toggler-toggle-collapsed").click();
}
function fix_dwds_ids() {
for (let e of document.querySelectorAll("a[href^='https://wikidata-externalid-url.toolforge.org/?p=9940&']")) {
e.href = e.href.replace(/.*&url_prefix=(.*?)&id=/, "$1").replace(/%23/, "#");
}
}
/* Link the datatype on property pages to the list of properties */
function link_property_datatype(e) {
if (e.type === "property") {
let t = document.querySelector(".wikibase-propertyview-datatype-value");
t.innerHTML = "<a href='/wiki/Special:ListProperties?datatype=" + e.datatype + "&limit=500'>" + t.textContent + "</a>";
}
}
/* Link sitelink language codes to the page to edit the label/desc/aliases for that language */
function link_sitelink_codes (e) {
mw.util.addCSS(".wikibase-sitelinkview-siteid-container a { color: inherit; }");
for (let el of document.querySelectorAll(".wikibase-sitelinkview")) {
const lang = el.querySelector("a[hreflang]").hreflang;
let a = document.createElement("a");
a.href = `/wiki/Special:SetLabelDescriptionAliases/${e.id}/${lang}`;
a.appendChild(el.querySelector(".wikibase-sitelinkview-siteid"));
el.querySelector(".wikibase-sitelinkview-siteid-container").appendChild(a);
}
}
// Link units in quantities to their items
function link_units(e) {
for (let st of Object.values(e.claims).flat()) {
replace_unit(st.mainsnak);
if (st.hasOwnProperty("qualifiers")) {
for (const q of Object.values(st.qualifiers).flat()) {
replace_unit(q);
}
}
}
}
function replace_unit(snak) {
if (snak.datatype === "quantity") {
if (snak.datavalue.value.unit.match(/^http:\/\/www.wikidata\.org\/entity\/Q[0-9]+$/)) {
const unit = snak.datavalue.value.unit.replace("http://www.wikidata.org/entity/", "/wiki/");
let el = document.querySelector(`.wikibase-snakview-${snak.hash} .wb-unit`);
el.innerHTML = `<a href="${unit}">${el.innerHTML}</a>`;
}
}
}
// Tag Klingon script more explicitly so that the right fonts can be used
function klingon_script() {
for (const el of document.querySelectorAll(":lang(mis-x-q56627865)")) {
el.lang = "tlh-piqd";
}
}
// Fix vertical scripts
function vertical_script() {
const map = {
"mong": /[\u1800-\u18AA]/,
"phag": /[\uA840-\uA87F]/,
};
for (let el of document.querySelectorAll(".wb-monolingualtext-value")) {
for (let [script, re] of Object.entries(map)) {
if (!el.textContent.match(re))
continue;
// Skip language codes with subtags
// TODO: Handle subtags
if (el.lang.length > 3)
continue;
el.lang = el.lang + "-" + script;
}
}
}
// Add tab on property pages linking to the constraint violations
// Make the property tab on property talk subpages point to the main property page
function property_tabs() {
var ns = mw.config.get("wgNamespaceNumber");
if (ns !== 120 && ns !== 121)
// not a property
return;
var title_parts = mw.config.get("wgTitle").split("/");
var id = title_parts[0];
// Add a tab linking to the constraint violations page
var href = "/wiki/Wikidata:Database_reports/Constraint_violations/" + id;
mw.util.addPortletLink("p-namespaces", href, "Constraints", "t-constraints", "Constraint violations report for this property");
// Make the property tab on subpages point to the main property page
if (title_parts.length > 1) {
var tab = document.querySelector("#ca-nstab-property a");
tab.href = "/wiki/Property:" + id;
// Remove the class which makes it a red link
// (the property is more likely to exist than not)
tab.parentNode.classList.remove("new");
}
}
// Render hiero syntax in P7383 (name in hiero syntax)
function render_hiero() {
var api = new mw.Api();
async function render_hiero_node(e) {
let text = "<hiero>" + e.textContent + "</hiero>";
let res = await api.get({
action: "parse",
contentmodel: "wikitext",
disablelimitreport: 1,
formatversion: 2,
prop: "text",
text: text,
wrapoutputclass: "hiero",
});
let hiero = res.parse.text;
e.innerHTML = hiero;
}
mw.util.addCSS(`
.hiero {
display: inline;
}
.mw-hiero-outer {
display: inline-block;
vertical-align: top;
}
.mw-hiero-table td {
text-align: center;
}
`);
for (let e of document.querySelectorAll(
"#P7383 .wikibase-statementview-mainsnak .wikibase-snakview-value,"
+ ".wikibase-statementgroupview[data-property-id=\"P7383\"] .wikibase-statementview-mainsnak .wikibase-snakview-value"
)) {
render_hiero_node(e);
}
for (let e of document.querySelectorAll(".wikibase-statementview-qualifiers a[href='/wiki/Property:P7383']")) {
render_hiero_node(e.parentNode.parentNode.parentNode.querySelector(".wikibase-snakview-value"));
}
}
// Replace Creative Commons license names with their abbreviations
// Currently not including country-specific versions
// Query for CC licenses and their abbreviations: https://w.wiki/6cX5
function shorten_creative_commons_names() {
const map = {
"Q6938433": "CC0",
"Q6905323": "CC BY",
"Q30942811": "CC BY 1.0",
"Q19125117": "CC BY 2.0",
"Q18810333": "CC BY 2.5",
"Q14947546": "CC BY 3.0",
"Q20007257": "CC BY 4.0",
"Q6936496": "CC BY-NC",
"Q44283370": "CC BY-NC 1.0",
"Q44128984": "CC BY-NC 2.0",
"Q19113746": "CC BY-NC 2.5",
"Q18810331": "CC BY-NC 3.0",
"Q34179348": "CC BY-NC 4.0",
"Q6937225": "CC BY-NC-ND",
"Q47008926": "CC BY-NC-ND 1.0",
"Q47008927": "CC BY-NC-ND 2.0",
"Q19068204": "CC BY-NC-ND 2.5",
"Q19125045": "CC BY-NC-ND 3.0",
"Q24082749": "CC BY-NC-ND 4.0",
"Q6998997": "CC BY-NC-SA",
"Q47008954": "CC BY-NC-SA 1.0",
"Q28050835": "CC BY-NC-SA 2.0",
"Q19068212": "CC BY-NC-SA 2.5",
"Q15643954": "CC BY-NC-SA 3.0",
"Q42553662": "CC BY-NC-SA 4.0",
"Q6999319": "CC BY-ND",
"Q47008966": "CC BY-ND 1.0",
"Q35254645": "CC BY-ND 2.0",
"Q18810338": "CC BY-ND 2.5",
"Q18810160": "CC BY-ND 3.0",
"Q36795408": "CC BY-ND 4.0",
"Q6905942": "CC BY-SA",
"Q47001652": "CC BY-SA 1.0",
"Q19068220": "CC BY-SA 2.0",
"Q19113751": "CC BY-SA 2.5",
"Q14946043": "CC BY-SA 3.0",
"Q18199165": "CC BY-SA 4.0",
"Q75209430": "CC SA 1.0",
};
const sel = Object.keys(map).map(a => `.wikibase-entityview a[href='/wiki/${a}']`).join(", ");
for (let e of document.querySelectorAll(sel)) {
e.textContent = map[e.href.replace(/.*\//, "")];
}
}
/* Shorten property proposal statements */
function shorten_prop_proposal_links() {
const elements = document.querySelectorAll("#P3254 .wikibase-statementview-mainsnak .wikibase-snakview-value a");
for (let e of elements) {
e.textContent = e.textContent.replace(/^https:\/\/www.wikidata.org\/wiki\/Wikidata:Property_proposal\//, "");
}
}
/* Replace language names with language codes in the translations box */
function shorten_translations_box() {
for (let e of document.querySelectorAll(".mw-pt-languages-list [lang]")) {
e.textContent = e.getAttribute("lang");
}
}
/* Show label language codes */
function show_label_language_codes() {
mw.util.addCSS(`
.langcode {
color: grey;
}
`);
$(".wikibase-entitytermsforlanguageview").each(function () {
var lang = $(this).find("[lang]:not('.wb-empty')").first().attr("lang");
var $td = $(this).find(".wikibase-entitytermsforlanguageview-language");
if ($td.find(".langcode").length) {
return;
}
$td.append(" <span class=\"langcode\">("+lang+")</span>");
});
}
/* Sort lexeme glosses alphabetically by language code,
add the language code after the language name
and put user languages at the top */
function sort_lexeme_glosses() {
if (mw.config.get("wgPageContentModel") !== "wikibase-lexeme") {
// Not a lexeme
return;
}
// Use slice() to copy the array, otherwise it changes the config variable
const senselangs = mw.config.get("wgULSBabelLanguages").slice().reverse();
mw.util.addCSS(`
.wikibase-lexeme-sense-gloss.n-highlight-row {
background-color: #d9f2d9;
}
.n-langcode {
color: grey;
font-size: small;
}
`);
$(".wikibase-lexeme-sense-glosses-table").each(function (i, v) {
// Sort lexeme glosses by language
$(v).find(".wikibase-lexeme-sense-gloss-value-cell")
.map(function (j, w) { return w.lang })
.sort()
.each(function (k, lang) {
var glossrow = $(v).find(".wikibase-lexeme-sense-gloss-value-cell[lang=" + lang + "]")
.closest(".wikibase-lexeme-sense-gloss");
$(glossrow).find(".wikibase-lexeme-sense-gloss-language")
.append(" <span class=\"n-langcode\">(" + lang + ")</span>");
$(v).append(glossrow);
});
// Put languages from the user's Babel box at the top and highlight them
for (var x = 0; x < senselangs.length; x++) {
var glossrow = $(v).find(".wikibase-lexeme-sense-gloss-value-cell[lang=" + senselangs[x] + "]")
.closest(".wikibase-lexeme-sense-gloss").addClass("n-highlight-row").prependTo(v);
}
});
}
/* Sort qualifier values */
function sort_qualifier_values() {
for (const e of document.querySelectorAll(".wikibase-snaklistview-listview")) {
let qualifiers = [...e.querySelectorAll(".wikibase-snakview")];
qualifiers.sort(function (a, b) {
// Select the value of the link, if present (e.g. entity
// datatypes), use the entire value if not
const sel = ".wikibase-snakview-value a, .wikibase-snakview-value";
const at = a.querySelector(sel).textContent;
const bt = b.querySelector(sel).textContent;
return at.localeCompare(bt);
});
for (const q of qualifiers) {
e.appendChild(q);
}
// Move the property to the first qualifier
const p1 = e.querySelector(".wikibase-snakview .wikibase-snakview-property-container .wikibase-snakview-property");
const pc1 = p1.parentNode;
const p2 = e.querySelector(".wikibase-snakview-property-container a").parentNode;
const pc2 = p2.parentNode;
pc1.insertAdjacentElement("afterbegin", p2);
pc2.insertAdjacentElement("afterbegin", p1);
}
}
function sort_statements_by_rank() {
$(".wikibase-statementgroupview .wikibase-statementlistview-listview").each(function() {
$(this).find(".wb-preferred").prependTo(this);
$(this).find(".wb-deprecated").appendTo(this);
});
}
/* Add property name to the page title on talk pages */
function talk_page_title() {
if (mw.config.get("wgNamespaceNumber") !== 121)
return;
const p = document.querySelector(".property-navibox-header div b");
if (!p)
return;
const pname = p.textContent;
document.getElementById("firstHeading").insertAdjacentText("beforeend", ` (${pname})`);
document.title = document.title.replace(/ - Wikidata$/, ` (${pname}) - Wikidata`);
}
/* Render title in HTML (P6833) as HTML */
function title_as_html() {
for (const e of document.querySelectorAll("a[title='Property:P6833']")) {
let n = e.parentNode.parentNode.parentNode.querySelector(".wb-monolingualtext-value");
// To avoid problems caused by bad HTML, this only replaces the
// elements allowed for this property, i.e. <sup>, <sub> and <i>
n.innerHTML = n.innerHTML.replace(/<(su[pb]|i)>([^<>]+?)<\/\1>/g, "<$1>$2</$1>");
}
}
/* Show MediaWiki version in footer */
async function display_mediawiki_version() {
await load_translations();
const footer = document.querySelector("#footer-info");
const text = $.i18n("version") + document.querySelector("meta[name='generator']").content;
const float = document.dir == "rtl" ? "left" : "right";
footer.insertAdjacentHTML("afterbegin", "<li style='float:" + float + "'>" + text + "</li>");
}
async function load_translations() {
// base URL has to end with .json, due to bad jquery.i18n assumptions
const translations = new mw.Title("User:Nikki/translations.json").getUrl() +
"?action=raw&ctype=application/json";
await $.i18n().load(translations);
}
property_tabs();
shorten_translations_box();
mw.loader.using("jquery.i18n").then(display_mediawiki_version);
mw.loader.using("jquery.i18n").then(talk_page_title);
mw.hook("wikibase.entityPage.entityView.rendered").add(add_tab_indexes);
mw.hook("wikibase.entityPage.entityView.rendered").add(add_debug_links);
mw.hook("wikibase.entityPage.entityView.rendered").add(better_url_display);
mw.hook("wikibase.entityPage.entityView.rendered").add(collapse_references);
mw.hook("wikibase.entityPage.entityView.rendered").add(display_colours);
mw.hook("wikibase.entityPage.entityView.rendered").add(display_statement_count);
mw.hook("wikibase.entityPage.entityView.rendered").add(expand_termbox);
mw.hook("wikibase.entityPage.entityView.rendered").add(fix_dwds_ids);
mw.hook("wikibase.entityPage.entityView.rendered").add(klingon_script);
mw.hook("wikibase.entityPage.entityView.rendered").add(render_hiero);
mw.hook("wikibase.entityPage.entityView.rendered").add(shorten_creative_commons_names);
mw.hook("wikibase.entityPage.entityView.rendered").add(shorten_prop_proposal_links);
mw.hook("wikibase.entityPage.entityView.rendered").add(sort_lexeme_glosses);
mw.hook("wikibase.entityPage.entityView.rendered").add(sort_qualifier_values);
mw.hook("wikibase.entityPage.entityView.rendered").add(sort_statements_by_rank);
mw.hook("wikibase.entityPage.entityView.rendered").add(title_as_html);
mw.hook("wikibase.entityPage.entityView.rendered").add(vertical_script);
mw.hook("wikibase.statement.saved").add(add_tab_indexes);
mw.hook("wikibase.statement.saved").add(fix_dwds_ids);
mw.hook("wikibase.statement.saved").add(vertical_script);
mw.hook("wikibase.entityPage.entityView.rendered").add(function () {
mw.hook("wikibase.entityPage.entityLoaded").add(link_property_datatype);
mw.hook("wikibase.entityPage.entityLoaded").add(link_sitelink_codes);
mw.hook("wikibase.entityPage.entityLoaded").add(link_units);
});
mw.hook("wikibase.entityPage.entityView.rendered").add(function () {
show_label_language_codes();
$(".wikibase-entitytermsforlanguagelistview-more a").click(function () { show_label_language_codes(); });
});
})();