Utente:Nastoshka/Wikidata Lookup.js

Da Wikisource.

Nota: dopo aver pubblicato, potrebbe essere necessario pulire la cache del proprio browser per vedere i cambiamenti.

  • Firefox / Safari: tieni premuto il tasto delle maiuscole Shift e fai clic su Ricarica, oppure premi Ctrl-F5 o Ctrl-R (⌘-R su Mac)
  • Google Chrome: premi Ctrl-Shift-R (⌘-Shift-R su un Mac)
  • Internet Explorer / Edge: tieni premuto il tasto Ctrl e fai clic su Aggiorna, oppure premi Ctrl-F5
  • Opera: premi Ctrl-F5.
/**
 * @author User:Nastoshka
 * @date 31-01-2024
 *
 * Feel free to use and modify this code and most importantly, have fun! (no guarantee, expcept for the fun part :D )
 * 
 * Very simple script to search on Wikidata for an item with a label in the selected language.
 *
 * It lets a button appear on the page, which when clicked, will search for the currently selected text on Wikidata.
 * If the search returns results, a modal window will appear with the results displaying:
 * - the Wikidata ID
 * - the label
 * - the description
 * 
 */

// Settings
const RESULT_LIMIT = 10; // Massimo numero di risultati da caricare da Wikidata
const BOTTOM_LEFT_POSITION = true; // Posiziona la finestra di ricerca in basso a sinistra, se "false" in alto accanto al titolo della pagina
const SEARCH_LANGUAGE = 'it'; // Lingua di ricerca (it, en, fr, ecc.) su Wikidata
if (mw.config.get('wgNamespaceNumber') == 0 || mw.config.get('wgNamespaceNumber') == 102 | mw.config.get('wgNamespaceNumber') == 108 || mw.config.get('wgNamespaceNumber') == 110 ) { 
// ------------------------------------------------------------
// Button
// ------------------------------------------------------------
// Stile del bottone
const btnStyle = {
    marginLeft: '10px',
    padding: '5px',
    backgroundImage: 'linear-gradient(#3670c8,#2282dc)',
    fontSize: '12px',
    fontWeight: 'bold',
    color: '#fff',
    borderRadius: '5px',
    border: 'none',
    cursor: 'pointer'
};
const searchButton = document.createElement('button');

searchButton.textContent = 'Wikidata Lookup'
searchButton.style.marginLeft = btnStyle.marginLeft;
searchButton.style.width = '150px';
searchButton.style.height = '30px';
searchButton.style.padding = btnStyle.padding;
searchButton.style.backgroundImage = btnStyle.backgroundImage;
searchButton.style.fontSize = btnStyle.fontSize;
searchButton.style.fontWeight = btnStyle.fontWeight;
searchButton.style.color = btnStyle.color;
searchButton.style.borderRadius = btnStyle.borderRadius;
searchButton.style.border = btnStyle.border;
searchButton.style.cursor = btnStyle.cursor;

// Aggancio il bottone al DOM
if (BOTTOM_LEFT_POSITION) {
    searchButton.style.position = 'fixed';
    searchButton.style.bottom = '20px';
    searchButton.style.left = '20px';
    document.body.appendChild(searchButton);
} else {
    const titleElement = document.getElementById('firstHeading');
    if (titleElement) {
        titleElement.appendChild(searchButton);
    } else {
        console.error('Impossibile agganciare il bottone. Controlla il codice.');
    }
}


/*
// ------------------------------------------------------------
// Modal window - Display the results
// ------------------------------------------------------------
 */
function showModal(items) {
    const modal = document.createElement('div');
    // Modal base styles
    modal.style.position = 'fixed';
    modal.style.left = '30vw';
    modal.style.top = '150px';
    modal.style.backgroundColor = 'rgba(0,0,0,0.5)';
    modal.style.display = 'flex';
    modal.style.justifyContent = 'center';
    modal.style.alignItems = 'center';
    modal.style.zIndex = '10000';
    modal.style.width = 'auto';
    modal.style.height = 'auto';
    modal.style.maxWidth = '60%';
    modal.style.maxHeight = '80%';
    modal.style.boxShadow = '2px 4px 4px 2px #c8ccd1';


    const content = document.createElement('div');
    // Content styles for flex grid
    content.style.display = 'flex';
    content.style.flexWrap = 'wrap';
    content.style.justifyContent = 'start'; // Align items to the start of the content box
    content.style.gap = '10px'; // Space between grid items
    content.style.backgroundColor = '#fff';
    content.style.padding = '20px';
    content.style.borderRadius = '5px';
    content.style.overflowY = 'auto';
    content.style.display = 'flex';
    content.style.flexDirection = 'column';
    content.style.alignItems = 'center';
    content.style.maxWidth = '600px';



    const closeButton = document.createElement('button');
    closeButton.textContent = 'Close';
    closeButton.style.marginTop = btnStyle.marginLeft;
    closeButton.style.padding = btnStyle.padding;
    closeButton.style.backgroundColor = 'rgba(248,56,56,0.8)';
    closeButton.style.color = ('#fff');
    closeButton.style.borderRadius = btnStyle.borderRadius;
    closeButton.style.border = btnStyle.border;
    closeButton.style.fontSize = btnStyle.fontSize;
    closeButton.style.fontWeight = btnStyle.fontWeight;
    closeButton.style.padding = '7px 15px';




    closeButton.onclick = function () {
        document.body.removeChild(modal);
    };

    content.appendChild(document.createElement('h2')).textContent = 'Risultati';
    content.appendChild(document.createElement('p')).innerHTML = "<strong><em>Clicca su un risultato per copiare l'ID Wikidata.</em></strong>";
    content.appendChild(document.createElement('hr'));

    const resultList = document.createElement('ul');
    resultList.style.listStyleType = 'none'; // Remove default list styling
    resultList.style.padding = '0';

items.forEach(item => {
    const itemPoint = document.createElement('li');
    itemPoint.style.margin = '10px 0'; // Add margin for separation between items
    itemPoint.style.cursor = 'pointer';

    const label = item.itemLabel ? item.itemLabel.value : "-- label assente --";
    const desc = item.itemDescription ? item.itemDescription.value : "-- descrizione assente --";
    const wikidataId = item.item.value.split('/').pop();

    itemPoint.textContent = `${wikidataId} : ${label} (${desc})`;
    itemPoint.onclick = () => {
        navigator.clipboard.writeText(wikidataId).then(() => {
            document.body.removeChild(modal);
        });
    };

    resultList.appendChild(itemPoint);
});

    content.appendChild(resultList);

    content.appendChild(closeButton);
    modal.appendChild(content);
    document.body.appendChild(modal);
}

// ------------------------------------------------------------
// Event listener - responsabile per la ricerca su Wikidata
// ------------------------------------------------------------
searchButton.addEventListener('click', function () {
    let selectedText = window.getSelection().toString().trim();

    if (!selectedText) {
        alert("Seleziona del testo prima di cliccare sul bottone ;)");
        return;
    }

    // Query SPARQL
    // https://www.wikidata.org/wiki/Wikidata:SPARQL_tutorial/it
    // La Query seguente cerca un item in Wikidata che abbia una label in italiano
    // e che abbia almeno una proprietà "wikisource" o "wikipedia".
    let query = `
  SELECT ?item ?itemLabel ?itemDescription WHERE {
  SERVICE wikibase:mwapi {
    bd:serviceParam wikibase:endpoint "www.wikidata.org";
                    wikibase:api "EntitySearch";
                    mwapi:search "${selectedText}";
                    mwapi:language "${SEARCH_LANGUAGE}".
    ?item wikibase:apiOutputItem mwapi:item.
  }
  OPTIONAL { ?item wdt:P31/wdt:P279* wd:Q5. BIND(1 AS ?priority) } # Higher priority to Human beings
  OPTIONAL { ?item wdt:P31/wdt:P279* wd:Q7725634. BIND(2 AS ?priority) } # Higher priority to Literary works
  OPTIONAL { ?item rdfs:label ?itemLabel. FILTER(LANG(?itemLabel) = "${SEARCH_LANGUAGE}") } # Label in the search language
  OPTIONAL { ?item schema:description ?itemDescription. FILTER(LANG(?itemDescription) = "${SEARCH_LANGUAGE}") } # Description in the search language
  OPTIONAL { ?item schema:name ?sitelink. FILTER(CONTAINS(LCASE(?sitelink), LCASE("${selectedText}")) && LANG(?sitelink) = "${SEARCH_LANGUAGE}") }
} ORDER BY ?priority LIMIT ${RESULT_LIMIT}
    `;

    let url = 'https://query.wikidata.org/sparql?query=' + encodeURIComponent(query) + '&format=json';
    fetch(url)
        .then(response => response.json())
        .then(data => {
            const results = data.results.bindings;
            console.log(data)
            if (results.length > 0) {
                showModal(results);
            } else {
                alert("Nessun risultato trovato.");
            }
        })
        .catch(error => {
            console.error('Error nel fetch dei dati: ', error);
            alert("Errore nel fetch dei dati. Controlla la console per maggiori informazioni.");
        });
});
}