User:Teester/CheckShex.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.
/**
* CheckShex.js adds an input box to a wikidata page wherein you can enter an entityschema
* (such as E10). When you clikc "Check", it uses pyshexy to validate the entity against
* the schema and displays whether the entity passes or fails.
**/
pyshexy_stylesheet = pyshexy_getStylesheet();
$('html > head').append("<style>" + pyshexy_stylesheet + "</style>");
var pyshexy_entitySchema;
var pyshexy_entity;
if (document.location.pathname.includes("EntitySchema")) {
// Get the entitySchema of the page
var pyshexy_entityschema_html = '<span><span id="simpleSearch"><span><input type="text" id="entityToCheck" placeholder="Enter an entity to check e.g.Q42"><input type="submit" id="schemaSearchButton" class="searchButton" onClick="pyshexy_update()" name="check" value="Check"></span></span><span id="entityCheckResponse"></span></span>';
var pyshexy_entitySchemaTitle = $(".entityschema-title-id" )[0].innerText;
pyshexy_entitySchema = pyshexy_entitySchemaTitle.substring(1, pyshexy_entitySchemaTitle.length-1);
$(".entityschema-schema-text-links" ).append( pyshexy_entityschema_html );
pyshexy_autocomplete(document.getElementById("entityToCheck"));
}
var pyshexy_conditions = ["/wiki/Q", "/wiki/P", "/wiki/L"];
if (pyshexy_conditions.some(el => document.location.pathname.includes(el))) {
var pyshexy_entity_html = '<div><span id="simpleSearch"><span><input type="text" id="entityToCheck" placeholder="Enter a schema to check against e.g. E10"><input type="submit" id="schemaSearchButton" class="searchButton" onClick="pyshexy_update()" name="check" value="Check"></span></span><span id="entityCheckResponse"></span></div>';
var titleId = $(".wikibase-title-id" )[0];
var pyshexy_entityTitle = titleId ? titleId.innerText : '';
pyshexy_entity = pyshexy_entityTitle.substring(1, pyshexy_entityTitle.length-1);
if (document.location.pathname.includes("/wiki/L")) {
$(".mw-indicators" ).append( pyshexy_entity_html );
} else {
$(".wikibase-entitytermsview-heading" ).append( pyshexy_entity_html );
}
}
function pyshexy_update() {
if (pyshexy_entitySchema) {
if ($("#entityToCheck")[0].attributes.wikidata) {
pyshexy_entity = $("#entityToCheck")[0].attributes.wikidata.value;
} else {
pyshexy_entitySchema = $("#entityToCheck")[0].value.toUpperCase();
}
} else {
pyshexy_entitySchema = $("#entityToCheck")[0].value.toUpperCase();
}
if (pyshexy_entitySchema && pyshexy_entity) {
pyshexy_checkEntity(pyshexy_entitySchema, pyshexy_entity);
}
}
function pyshexy_checkEntity(entitySchema, entity) {
$("#entityCheckResponse").contents().remove();
var url = "https://tools.wmflabs.org/pyshexy/api?entityschema=" + entitySchema + "&entity=" + entity;
$.ajax({
type: "GET",
dataType: "json",
url: url,
success: function(data){
var html = "";
if (data.results[0].result) {
html = '<span class="response"><span class="pass">✔</span><span> Pass</span></span>';
} else {
html = pyshexy_parseResult(data.results[0]);
console.log(data.results[0].reason);
}
$("#entityCheckResponse" ).append( html );
},
error: function(data) {
$("#entityCheckResponse" ).append( '<span>Unable to validate schema</span>' );
}
});
}
function pyshexy_getStylesheet() {
var stylesheet = "#schemaSearchButton { background-position: center center; background-repeat: no-repeat; position: absolute; top:0; right:0; overflow: hidden; height:100%; background-color: #1E90FF !important; color: #FFFFFF !important; padding: 2px !important}";
stylesheet += "#entityToCheck { padding: 1em; margin:0; width: 100%;}";
stylesheet += ".response { padding: 2px;}";
stylesheet += ".pass { color: #008800; }";
stylesheet += ".fail { color: #CC0000; }";
stylesheet += ".missing { background-color: #CC0000; color: #ffffff; padding:2px; margin: 2px; font-size:75%; border-radius:2px;}";
return stylesheet;
}
function pyshexy_parseResult(data) {
var property = [];
var html = '<span class="response" title="' + data.reason + '"><span class="fail">✘</span><span class="response"> Fail</span>';
var no_matching_triples = "No matching triples found for predicate";
if (data.reason.includes(no_matching_triples)) {
property = data.reason.match(/P\d+/g);
}
if (property !== null) {
property = property.reduce(function(a,b){if(a.indexOf(b)<0)a.push(b);return a;},[]);
for (var i = 0; i < property.length; i++) {
html += '<span class="missing"> Missing valid ' + property[i] + '</span>';
}
}
html += "</span>";
return html;
}
/**
* This function handles all aspects of Autocomplete
*
**/
function pyshexy_autocomplete(inp) {
/*the autocomplete function takes two arguments,
the text field element and an array of possible autocompleted values:*/
var currentFocus;
/*execute a function when someone writes in the text field:*/
inp.addEventListener("input", function(e) {
var a, b, i, val = this.value;
/*close any already open lists of autocompleted values*/
closeAllLists();
if (!val) { return false;}
currentFocus = -1;
/*create a DIV element that will contain the items (values):*/
a = document.createElement("DIV");
a.setAttribute("id", this.id + "autocomplete-list");
a.setAttribute("class", "autocomplete-items ui-suggester-list");
/*append the DIV element as a child of the autocomplete container:*/
this.parentNode.appendChild(a);
if (val.length>2){
// get array
$.ajax({
type: "GET",
dataType: "json",
url: "https://www.wikidata.org/w/api.php?action=wbsearchentities&search="+val+"&language=en&origin=*&format=json",
success: function(data){
arr = data.search;
/*for each item in the array...*/
for (i = 0; i < arr.length; i++) {
/*check if the item starts with the same letters as the text field value:*/
/*create a DIV element for each matching element:*/
b = document.createElement("DIV");
/*make the matching letters bold:*/
b.innerHTML = "<span class='autocomplete-label ui-entityselector-label'>" + arr[i].label + "</span>";
if (arr[i].description) {
b.innerHTML += "<br/><span class='description ui-entityselector-description'>" + arr[i].description + "</span>";
}
/*insert a input field that will hold the current array item's value:*/
b.innerHTML += "<input type='hidden' value='" + arr[i].label + " (" + arr[i].id + ")'>";
b.innerHTML += "<input type='hidden' value='" + arr[i].id + "'>";
/*execute a function when someone clicks on the item value (DIV element):*/
b.addEventListener("click", function(e) {
/*insert the value for the autocomplete text field:*/
inp.value = this.getElementsByTagName("input")[0].value;
inp.setAttribute("wikidata", this.getElementsByTagName("input")[1].value);
/*close the list of autocompleted values,
(or any other open lists of autocompleted values:*/
closeAllLists();
});
a.appendChild(b);
}
}
});
}
});
/*execute a function presses a key on the keyboard:*/
inp.addEventListener("keydown", function(e) {
var x = document.getElementById(this.id + "autocomplete-list");
if (x) x = x.getElementsByTagName("div");
if (e.keyCode == 40) {
/*If the arrow DOWN key is pressed,
increase the currentFocus variable:*/
currentFocus++;
/*and and make the current item more visible:*/
addActive(x);
} else if (e.keyCode == 38) { //up
/*If the arrow UP key is pressed,
decrease the currentFocus variable:*/
currentFocus--;
/*and and make the current item more visible:*/
addActive(x);
} else if (e.keyCode == 13) {
/*If the ENTER key is pressed, prevent the form from being submitted,*/
e.preventDefault();
if (currentFocus > -1) {
/*and simulate a click on the "active" item:*/
if (x) x[currentFocus].click();
}
}
});
function addActive(x) {
/*a function to classify an item as "active":*/
if (!x) return false;
/*start by removing the "active" class on all items:*/
removeActive(x);
if (currentFocus >= x.length) currentFocus = 0;
if (currentFocus < 0) currentFocus = (x.length - 1);
/*add class "autocomplete-active":*/
x[currentFocus].classList.add("autocomplete-active");
}
function removeActive(x) {
/*a function to remove the "active" class from all autocomplete items:*/
for (var i = 0; i < x.length; i++) {
x[i].classList.remove("autocomplete-active");
}
}
function closeAllLists(elmnt) {
/*close all autocomplete lists in the document,
except the one passed as an argument:*/
var x = document.getElementsByClassName("autocomplete-items");
for (var i = 0; i < x.length; i++) {
if (elmnt != x[i] && elmnt != inp) {
x[i].parentNode.removeChild(x[i]);
}
}
}
/*execute a function when someone clicks in the document:*/
document.addEventListener("click", function (e) {
closeAllLists(e.target);
});
}