MediaWiki:CustomExtensions: Difference between revisions
From semantic-hub.io
No edit summary |
No edit summary |
||
| Line 237: | Line 237: | ||
let url = "https://semantic-hub.io/entityshape/api/v2?entityschema=" + entitySchema + "&entity=" + entity + "&language=" + language; | let url = "https://semantic-hub.io/entityshape/api/v2?entityschema=" + entitySchema + "&entity=" + entity + "&language=" + language; | ||
// let url = "https://entityshape.toolforge.org/api/v2?entityschema=" + entitySchema + "&entity=" + entity + "&language=" + language; | |||
// let url = "http://127.0.0.1:5000/api/v2 ?entityschema=" + entitySchema + "&entity=" + entity + "&language=" + language; | // let url = "http://127.0.0.1:5000/api/v2 ?entityschema=" + entitySchema + "&entity=" + entity + "&language=" + language; | ||
$.ajax({ | $.ajax({ | ||
Latest revision as of 22:32, 6 February 2026
/* Any JavaScript here will be loaded for all users on every page load. */
/**
* EntitySchema Enhancement Scripts * Loaded for all users automatically */
// Load EntitySchemaHighlighter // ---------------------------- // Source: https://www.wikidata.org/wiki/User:Zvpunry/EntitySchemaHighlighter.js
$(function() {
const entityRegEx = /\b[PQ]\d+(?=\b|_)/g; const scriptName = 'SchemaItemPropertyHighlighter';
function markupEntities(html, entitiesData) {
return html.replace(entityRegEx, function(match) {
if (
!entitiesData[match] ||
typeof entitiesData[match].missing !== 'undefined'
) {
return match;
}
return $('<a>')
.attr({
href: 'https://semantic-hub.io/wiki/' + entitiesData[match].title,
title: entitiesData[match].labels.en.value,
})
.text(match)[0].outerHTML;
});
}
async function requestEntitiesData(listOfEntities) {
const entityBatches = splitIntoBatches(listOfEntities);
const data = {};
for (const batch of entityBatches) {
let dataBatch = await requestBatchEntitiesData(batch);
Object.assign(data, dataBatch);
}
return data; }
async function requestBatchEntitiesData(listOfEntities) {
const urlBase = 'https://semantic-hub.io/w/api.php';
const urlParams = {
action: 'wbgetentities',
ids: listOfEntities.join('|'),
props: 'labels|info',
languages: 'en',
format: 'json',
origin: '*',
};
return fetch(urlBase + '?' + jQuery.param(urlParams))
.then(function(response) {
return response.json();
})
.then(function(responseData) {
if (responseData.error) {
console.warn('Error in userscript: ' + scriptName);
console.warn({
code: responseData.error.code,
info: responseData.error.info,
servedby: responseData.servedby,
});
return;
}
return responseData.entities;
});
}
function splitIntoBatches(listOfEntities) {
const maxBatchSize = 50.0;
return listOfEntities.reduce((acc, cur, i) => {
const index = Math.floor(i / maxBatchSize);
if (!acc[index]) {
acc[index] = [];
}
acc[index].push(cur);
return acc;
}, []);
}
function getListOfEntitiesFromSchemaText(schemaText) {
return [...new Set(schemaText.match(entityRegEx))];
}
const $schemaText = $('#entityschema-schema-text');
if (!$schemaText.length || !$schemaText.text().length) {
return;
}
const listOfEntities = getListOfEntitiesFromSchemaText($schemaText.html());
if (!listOfEntities.length) {
return;
}
requestEntitiesData(listOfEntities)
.then(function(responseData) {
$schemaText.html(markupEntities($schemaText.html(), responseData));
})
.catch(function(error) {
console.warn('Error in userscript: ' + scriptName);
console.warn(error);
});
});
// Load EntityShape validator // -------------------------- // Source: https://www.wikidata.org/wiki/User:Teester/EntityShape.js /**
* EntityShape.js adds an input box to a wikidata page wherein you can enter an entityschema * (such as E10). When you click "Check", checks whether each statement and property conforms * to the schema. It then displays a summary at the top of the item for each property indicating * whether they conform or not. It also adds a badge to each statement and each property on the * page indicating whether they conform or not. **/
(function() {
"use strict";
mw.util.addCSS(entityschema_getStylesheet());
let entityschema_list = [];
let value = mw.storage.get("entityschema-auto");
let schema = mw.storage.get("entityschema");
let lang = mw.config.get( 'wgUserLanguage' );
let property_list = [];
mw.hook( 'wikibase.entityPage.entityLoaded' ).add( function ( data ) {
let valid_values = ['item', 'lexeme', 'property'];
if (!valid_values.includes(data["type"])) { return; }
mw.util.addSubtitle(entityschema_getHTML());
$("#entityschema-checkbox").prop('checked', value);
$("#entityschema-schemaSearchButton").click(function(){ entityschema_update(); });
$("#entityschema-checkbox").click(function() { entityschema_checkbox(); });
let claims = data["claims"];
for (let claim in claims) {
property_list.push(claim);
let statements = claims[claim];
for (let statement in statements) {
let mainsnak = statements[statement]["mainsnak"];
if (mainsnak["datavalue"] && mainsnak["datatype"] == "wikibase-item") {
if (!property_list.includes(mainsnak["datavalue"]["value"]["id"])) {
property_list.push(mainsnak["datavalue"]["value"]["id"]);
}
}
}
}
check_entity_for_schemas(property_list);
});
mw.hook( 'wikibase.statement.saved' ).add( function ( data ) {
if (value == "true") {
entityschema_update();
}
});
mw.hook( 'wikibase.statement.removed' ).add( function ( data ) {
if (value == "true") {
entityschema_update();
}
});
function check_entity_for_schemas(entity_list) {
const api = new mw.Api({'User-Agent': 'Userscript Entityshape by User:Teester'});
for (let item in entity_list) {
api.get({
action: 'wbgetclaims',
property: 'P12861',
entity: entity_list[item],
format: 'json'})
.fail(function() { console.log("failed to get schemas") })
.done(function(data) {
if (data["claims"].hasOwnProperty("P12861")) {
let claims = data["claims"]["P12861"];
for (let claim in claims) {
entityschema_list.push(claims[claim]["mainsnak"]["datavalue"]["value"]["id"]);
}
}
});
}
}
$(document).ajaxStop(function () {
if (entityschema_list.length != 0) {
$('#entityschema-entityToCheck').attr("placeholder", entityschema_translate("Check against", entityschema_list.join(', ') ) );
}
if (value == "true" && mw.config.get( 'wbEntityId' )) {
entityschema_update();
}
$("#entityschema-entityToCheck:text").val(schema);
$(this).unbind('ajaxStop');
});
$("#entityschema-entityToCheck").on("keyup", function(event){
if (event.key === "Enter") {
event.preventDefault();
$("#entityschema-schemaSearchButton").click();
return false;
}
});
function entityschema_update() {
let entityschema_entitySchema = $("#entityschema-entityToCheck")[0].value.toUpperCase();
if (entityschema_entitySchema.length == 0) {
entityschema_entitySchema = entityschema_list.join(", ");
mw.storage.remove("entityschema");
} else {
mw.storage.set("entityschema", entityschema_entitySchema);
}
if (entityschema_entitySchema.length == 0) {
let message = new OO.ui.MessageWidget( {type: 'error', inline: true,
label: entityschema_translate('No schemas entered and could not automatically determine schemas to check') } );
$("#entityschema-response").empty().prepend( message.$element );
} else {
let entityschema_entityName = document.location.pathname.substring(6);
entityschema_checkEntity(entityschema_entityName, entityschema_entitySchema, lang);
}
}
function entityschema_checkbox() {
if ($('#entityschema-checkbox').is(":checked")) {
mw.storage.set("entityschema-auto", true);
} else {
mw.storage.set("entityschema-auto", false);
}
}
function entityschema_checkEntity(entity, entitySchema, language) {
$("#entityschema-response").contents().remove();
$(".entityschema-property").remove();
$(".entityschema-span").remove();
let url = "https://semantic-hub.io/entityshape/api/v2?entityschema=" + entitySchema + "&entity=" + entity + "&language=" + language;
// let url = "https://entityshape.toolforge.org/api/v2?entityschema=" + entitySchema + "&entity=" + entity + "&language=" + language; // let url = "http://127.0.0.1:5000/api/v2 ?entityschema=" + entitySchema + "&entity=" + entity + "&language=" + language; $.ajax({ type: "GET", dataType: "json", url: url, beforeSend: function() { $(".entityshape-spinner").show(); }, success: function(data){ for (let i = 0; i < data.schema.length; i++ ) { if (data.properties[i]) { entityschema_add_to_properties(data.properties[i], data.schema[i], data.name[i]); } if (data.statements[i]) { entityschema_add_to_statements(data.statements[i], data.schema[i], data.name[i]); } if (data.general[i]) { entityschema_add_general(data.general[i]); } }
const combined_properties = entityschema_combine_properties(data.properties, data.schema);
let message_data = [];
for (let schema in data.schema) {
message_data.push(`<a href='https://semantic-hub.io/wiki/EntitySchema:${data.schema[schema]}'>
${data.name[schema]} (${data.schema[schema]})</a>`);
}
let message = `${entityschema_translate('Checking against', message_data.join(', '))}:`;
let message_widget = new OO.ui.MessageWidget( {type: 'notice', inline: true,
label: new OO.ui.HtmlSnippet( message )} );
$("#entityschema-response" ).append( message_widget.$element );
let html = `
`;
html += entityschema_process_combined_properties(combined_properties);
$("#entityschema-response" ).append( html );
$(".entityshape-spinner").hide();
},
error: function(data) {
let message = new OO.ui.MessageWidget( {type: 'error', inline: true,
label: 'Unable to validate schema'} );
$("#entityschema-response" ).append( message.$element );
$(".entityshape-spinner").hide();
}
});
}
function entityschema_process_combined_properties(properties) {
let required_html = '";
optional_html += "";
absent_html += "";
let html = required_html + optional_html + absent_html + '
| ${entityschema_translate("Required properties")} | ${entityschema_translate("Optional properties")} | ${entityschema_translate("Other properties")} |
|---|---|---|
|
|
let other_array = [];
let other_array_names = [];
for (let key in properties) {
let shape_html = "";
let response1 = properties[key].response.combined;
let response_class = "";
let response_string = properties[key].response.combined;
switch (response1) {
case "present":
response_class = "present";
response_string = entityschema_translate("present");
break;
case "allowed":
response_class = "present";
response_string = entityschema_translate("present");
break;
case "correct":
response_class = "correct";
response_string = entityschema_translate("correct");
break;
case "missing":
response_class = "missing";
response_string = entityschema_translate("missing");
break;
default:
response_class = "wrong";
response_string = entityschema_translate("wrong");
break;
}
if (properties[key].necessity.combined == "absent") {
if (response1 == "too many statements") {
response1 = "not allowed";
response_string = entityschema_translate("not allowed");
}
}
if (!response1) {
response1 = "Not in schema";
response_string = entityschema_translate("Not in schema");
response_class = "notinschema";
}
let schema_link = `${properties[key].name} (${key})`;
if (response1 == null) {
response1 = "";
shape_html += `<a href="https://semantic-hub.io/wiki/Property:${key}">${schema_link}</a>
shape_html += `
|
';
return html; }
function entityschema_add_to_properties(properties, schema, name) {
for (let key in properties) {
let response = properties[key].response;
let response_class = "";
switch (response) {
case "present":
response_class = "present";
break;
case "correct":
response_class = "correct";
break;
case "missing":
response_class = "missing";
break;
default:
response_class = "wrong";
break;
}
if (properties[key].necessity == "absent") {
if (response == "too many statements") {
response = "not allowed";
}
}
if (!response) {
response = "Not in schema";
response_class = "notinschema";
}
if (response == null) {
response = "Not in schema";
response_class = "notinschema";
}
if (response != "Not in schema" && $("#" + key)[0]) {
let html =`
${schema}: ${response}
`;
$(`#${key} .wikibase-statementgroupview-property-label`).append(html);
}
}
}
function entityschema_add_to_statements(statements, schema, name) {
for (let statement in statements) {
let response = statements[statement].response;
if (response != "not in schema") {
let html = `
${schema}: ${response}
`;
$(`div[id='${statement}'] .wikibase-toolbar-button-edit`).append(html);
}
}
}
function entityschema_add_general(general) {
if (general.language) {
entityschema_add_general_item("language", general.language);
}
if (general.lexicalCategory) {
entityschema_add_general_item("lexical_category", general.lexicalCategory);
}
}
function entityschema_add_general_item(general_type, response) {
if (response != "not in schema") {
html = `
${response}
`;
$(`span[class='language-lexical-category-${general_type}']`).append(html);
}
}
function entityschema_combine_properties(property, schema) {
let combined_properties = {};
for (let i = 0; i < schema.length; i++ ) {
for (let key in property[i]) {
if(!combined_properties.hasOwnProperty(key)){ combined_properties[key] = {}; }
combined_properties[key]["name"] = property[i][key]["name"];
if(!combined_properties[key].hasOwnProperty("response")) { combined_properties[key]["response"] = {}; }
combined_properties[key]["response"][schema[i]] = property[i][key]["response"];
if(!combined_properties[key].hasOwnProperty("necessity")) { combined_properties[key]["necessity"] = {}; }
combined_properties[key]["necessity"][schema[i]] = property[i][key]["necessity"];
}
}
for (let key in combined_properties) {
let necessity = "absent";
let response = "";
let response_key = combined_properties[key]["response"];
let necessity_key = combined_properties[key]["necessity"];
if (Object.values(necessity_key).includes("required")) {
necessity = "required";
} else if (Object.values(necessity_key).includes("optional")) {
necessity = "optional";
}
if (Object.values(response_key).includes("incorrect")) {
response = "incorrect";
} else if (Object.values(response_key).includes("missing")) {
response = "missing";
} else if (Object.values(response_key).includes("too many statements")) {
response = "too many statements";
} else if (Object.values(response_key).includes("not enough statements")) {
response = "not enough statements";
} else if (Object.values(response_key).includes("correct")) {
response = "correct";
} else if (Object.values(response_key).includes("present")) {
response = "present";
} else if (Object.values(response_key).includes("allowed")) {
response = "present";
}
combined_properties[key]["response"]["combined"] = response;
combined_properties[key]["necessity"]["combined"] = necessity;
}
return combined_properties;
}
function entityschema_translate(phrase, variable="") {
const translations = {
"en": {
// Strings in the checking UI
"Enter schema to check against": "Enter schema to check against e.g. E234",
"Check against entityschema": "Check against entityschema",
"Check against" : `Check against ${variable}`,
"Checking against": `Checking against ${variable}`,
"Check": "Check",
"Automatically check schema": "Automatically check schema",
"Unable to validate schema": "Unable to validate schema",
"No schemas entered and could not automatically determine schemas to check": "No schemas entered and could not automatically determine schemas to check",
// Strings in the results section UI
"Properties in this item which must be present": "Properties in this item which must be present",
"Required properties": "Required properties",
"Properties in this item which can be present but do not have to be": "Properties in this item which can be present but do not have to be",
"Optional properties": "Optional properties",
"Properties in this item which are not allowed to be present or not mentioned in the entityschema": "Properties in this item which are not allowed to be present or not mentioned in the entityschema",
"Other properties": "Other properties",
"properties not in any schema checked": `${variable} properties not in any schema checked`,
// Strings for results
"present": "present",
"correct": "correct",
"missing": "missing",
"wrong": "wrong",
"absent": "absent",
"too many statements": "too many statements",
"not allowed": "not allowed",
"Not in schema": "Not in schema"
},
"ga": {
// Strings in the checking UI
"Enter schema to check against": "Cuir scéima isteach chun seiceáil m.sh. E234",
"Check against entityschema": "Seiceáil trí scéim eintitis",
"Check against" : `Seiceáil trí ${variable}`,
"Checking against": `Ag seiceáil trí ${variable}`,
"Check": "Seiceáil",
"Automatically check schema": "Seiceáil scéima go huathoibríoch",
"Unable to validate schema": "Ní féidir scéima bailíochtú",
"No schemas entered and could not automatically determine schemas to check": "Níor iontráladh aon scéimeanna agus níorbh fhéidir scéimeanna le seiceáil a chinneadh go huathoibríoch",
// Strings in the results section UI
"Properties in this item which must be present": "Airíonna sa mhír seo nach mór a bheith i láthair",
"Required properties": "Airíonna riachtanacha",
"Properties in this item which can be present but do not have to be": "Airíonna sa mhír seo a fhéadfaidh a bheith i láthair ach nach gá a bheith ann",
"Optional properties": "Airíonna roghnacha",
"Properties in this item which are not allowed to be present or not mentioned in the entityschema": "Airíonna sa mhír seo nach gceadaítear dóibh a bheith i láthair nó nach luaitear sa scéim eintitis",
"Other properties": "Airíonna eile",
"properties not in any schema checked": `Bhí ${variable} airíonna nach raibh in aon scéim seicáilte`,
// Strings for results
"present": "ann",
"correct": "ceart",
"missing": "ar iarraidh",
"wrong": "míceart",
"absent": "as lathair",
"too many statements": "an iomarca ráiteas",
"not allowed": "ní cheadaítear",
"Not in schema": "ní sa scéim"
}
};
let language = "en";
if (translations.hasOwnProperty(lang)) {
language = lang;
}
return translations[language][phrase];
}
function entityschema_getStylesheet() {
const entityschema_stylesheet = `#entityschema-simpleSearch { width:500px; }
#entityschema-response { padding:5px; display: block; }
.entityschema-summary { color: var(--color-progressive,#0645ad); }
a.is_entityschema-present { color: #008800; }
a.is_entityschema-allowed { color: #008800; }
a.is_entityschema-correct { color: #00CC00; }
a.is_entityschema-missing { color: #FF5500; }
a.is_entityschema-notinschema { color: #FF5500; }
a.is_entityschema-wrong { color: #CC0000; }
a.is_entityschema-wrong_amount { color: #CC0000; }
a.is_entityschema-incorrect { color: #CC0000; }
.entityschema_table {vertical-align: top; width: 33%; }
.entityschema-missing { background-color: #FF8C00; }
.entityschema-notinschema { background-color: #FF8C00; }
.entityschema-wrong { background-color: #CC0000; }
.entityschema-incorrect { background-color: #CC0000; }
.entityschema-wrong_amount { background-color: #CC0000; }
.entityschema-excess { background-color: #CC0000; }
.entityschema-deficit { background-color: #CC0000; }
.entityschema-present { background-color: #008800; }
.entityschema-allowed { background-color: #008800; }
.entityschema-correct { background-color: #00CC00; }
.required .entityschema-missing { background-color: #FF0000;}
.required a.is_entityschema-missing { color: #FF0000;}
.absent .entityschema-missing { display: none;}
.absent a.is_entityschema-missing { display: none;}
.entityschema-span { color: #ffffff; padding:2px; margin: 2px; font-size:75%; border-radius:2px; }
.entityshape-spinner,.entityshape-spinner div,.entityshape-spinner div:after {box-sizing: border-box;}
.entityshape-spinner { padding-top:5px; padding-bottom:5px; color: currentColor; display: inline-block; position: relative; width: 20px; height: 20px;}
.entityshape-spinner div { transform-origin: 10px 10px; animation: entityshape-spinner 1.2s linear infinite;}
.entityshape-spinner div:after { content: " "; display: block; position: absolute; top: 0.8px; left: 9.2px; width: 1.6px; height: 4.4px; border-radius: 20%; background: currentColor;}
.entityshape-spinner div:nth-child(1) { transform: rotate(0deg); animation-delay: -1.1s;}
.entityshape-spinner div:nth-child(2) { transform: rotate(30deg); animation-delay: -1s;}
.entityshape-spinner div:nth-child(3) { transform: rotate(60deg); animation-delay: -0.9s;}
.entityshape-spinner div:nth-child(4) { transform: rotate(90deg); animation-delay: -0.8s;}
.entityshape-spinner div:nth-child(5) { transform: rotate(120deg); animation-delay: -0.7s;}
.entityshape-spinner div:nth-child(6) { transform: rotate(150deg); animation-delay: -0.6s;}
.entityshape-spinner div:nth-child(7) { transform: rotate(180deg); animation-delay: -0.5s;}
.entityshape-spinner div:nth-child(8) { transform: rotate(210deg); animation-delay: -0.4s;}
.entityshape-spinner div:nth-child(9) { transform: rotate(240deg); animation-delay: -0.3s;}
.entityshape-spinner div:nth-child(10) { transform: rotate(270deg); animation-delay: -0.2s;}
.entityshape-spinner div:nth-child(11) { transform: rotate(300deg); animation-delay: -0.1s;}
.entityshape-spinner div:nth-child(12) { transform: rotate(330deg); animation-delay: 0s;}
@keyframes entityshape-spinner { 0% { opacity: 1; } 100% { opacity: 0; }}`;
return entityschema_stylesheet;
}
function entityschema_getHTML() {
const entityschema_results_html = `<details open style='box-shadow: 0 1px var(--border-color-subtle,#c8ccd1);'>
<summary class='entityschema-summary'>${entityschema_translate("Check against entityschema")}</summary>
<label class="oo-ui-labelElement-label">${entityschema_translate("Automatically check schema")}</label>
</details>`;
return entityschema_results_html;
}
}());
