User:Lockal/Gadget-relateditems.js

From Wikidata
Jump to navigation Jump to search

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 gadget displays related items on an item page.                                        *
*                                                                                            *
* How to use :  Go to [[Special:Preferences#mw-prefsection-gadgets]] and set a checkmark     *
*               on "relateditems".                                                           *
*                                                                                            *
**********************************************************************************************/

(function (mw, $, wb) {
    "use strict";

    if (mw.config.get('wgNamespaceNumber') !== 0 || !mw.config.exists('wbEntityId')) {
        return;
    }

    var lang = mw.config.get('wgUserLanguage');
    var messages, entityid = mw.config.get('wbEntityId'), api = new mw.Api();

    messages = (function () {
        var translations = {
            de: {
                'title': 'Abgeleitete Aussagen',
                'more': 'mehr',
                'inverse': 'invers',
                'show-inverse': 'zeige abgeleitete Aussagen',
                'show-inverse-commons': 'zeige abgeleitete Aussagen (Commons)',
                'no-result': 'kein Ergebnis',
                'loading': 'laden...'
            },
            en: {
                'title': 'Derived statements',
                'more': 'more',
                'inverse': 'inverse',
                'show-inverse': 'show derived statements',
                'show-inverse-commons': 'show derived statements (Commons)',
                'no-result': 'no result',
                'loading': 'loading...'
            },
            fr: {
                'title': 'Déclarations dérivées',
                'more': 'plus',
                'inverse': 'inverse',
                'show-inverse': 'voir les déclarations dérivées',
                'show-inverse-commons': 'voir les déclarations dérivées (Commons)',
                'no-result': 'pas de résultats',
                'loading': 'chargement...'
            },
            nb: {
                'title': 'avledet-utsagn',
                'more': 'mer',
                'inverse': 'invers',
                'show-inverse': 'vis inverse utsagn',
                'show-inverse-commons': 'vis inverse utsagn (Commons)',
                'no-result': 'ingen resultat',
                'loading': 'laster...'
            },
            sv: {
                'title': 'Härledda uttalanden',
                'more': 'mer',
                'inverse': 'omvänt',
                'show-inverse': 'visa härledda uttalanden',
                'show-inverse-commons': 'visa härledda uttalanden (Commons)',
                'no-result': 'inget resultat',
                'loading': 'laddar...'
            },
            'zh-hans': {
                'title': '派生陈述',
                'more': '更多',
                'inverse': '反向',
                'show-inverse': '显示派生陈述',
                'show-inverse-commons': '显示派生陈述 (Commons)',
                'no-result': '无结果',
                'loading': '加载中...'
            },
        },
            chain = mw.language.getFallbackLanguageChain(),
            len = chain.length,
            ret = {},
            i = len - 1;
        while (i >= 0) {
            if (translations.hasOwnProperty(chain[i])) {
                $.extend(ret, translations[chain[i]]);
            }
            i = i - 1;
        }
        return ret;
    }());

    var wdTemplate = 'SELECT DISTINCT ?subject ?subjectLabel ?property ?inversepropertyLabel ?rank WHERE {{\
        SELECT ?subject ?property ?inverseproperty ?rank WHERE { \
           ?subject ?claimpred ?statement .\
        ?statement ?valpred wd:%entityid% ;\
                  wikibase:rank ?rank .\
        ?property wikibase:claim ?claimpred;\
                  wikibase:statementProperty ?valpred;\
                  wdt:P7087 ?inverseproperty .\
        } LIMIT 300 }\
        SERVICE wikibase:label {bd:serviceParam wikibase:language "%lang%,en" .}\
    } ORDER BY ?property';
    var wdEndpoint = 'https://query.wikidata.org/bigdata/namespace/wdq/sparql';
    var wdMoreLinkTemplate = 'https://query.wikidata.org/#SELECT%20%3Fitem%20%3FitemLabel%20%3Fproperty%20%3Frank%0AWITH%20%7B%0A%20%20SELECT%20%3Fitem%20%3Fproperty%20%3Frank%20%7B%0A%20%20%20%20hint%3AQuery%20hint%3Aoptimizer%20%22None%22.%0A%20%20%20%20%3Fstatement%20%3Fvalpred%20wd%3A%entityid%%20.%0A%20%20%20%20%3Fstatement%20wikibase%3Arank%20%3Frank%20.%0A%20%20%20%20%3Fproperty%20wikibase%3AstatementProperty%20%3Fvalpred%20.%0A%20%20%20%20%3Fproperty%20wikibase%3Aclaim%20%3Fclaimpred%20.%0A%20%20%20%20%3Fitem%20%3Fclaimpred%20%3Fstatement%20.%0A%20%20%7D%20LIMIT%201000%0A%7D%20AS%20%25items%0A%7B%0A%20%20INCLUDE%20%25items%0A%20%20SERVICE%20wikibase%3Alabel%20%7B%20bd%3AserviceParam%20wikibase%3Alanguage%20%22en%22%20%7D%0A%7D%0A';

    var wcqsTemplate = 'SELECT ?subject ?subjectLabel ?property ?inversepropertyLabel ?rank\
    WITH {\
      SELECT ?valpred ?inversepropertyLabel {\
        SERVICE <https://query.wikidata.org/sparql> {\
          ?property wikibase:statementProperty ?valpred ; wdt:P7087 ?inverseproperty .\
          SERVICE wikibase:label {\
            bd:serviceParam wikibase:language "%lang%,en" .\
            ?inverseproperty rdfs:label ?inversepropertyLabel .\
          }\
        }\
      }\
    } AS %inverses\
    {\
      hint:Query hint:optimizer "None".\
      ?statement ?valpred wd:%entityid% .\
      INCLUDE %inverses\
      ?statement wikibase:rank ?rank .\
      ?subject ?claimpred ?statement .\
      ?subject schema:contentUrl ?url .\
      BIND(wikibase:decodeUri(CONCAT("File:", substr(str(?url),53))) AS ?subjectLabel)\
      BIND(URI(REPLACE(STR(?valpred), "http://www.wikidata.org/prop/statement/", "http://www.wikidata.org/entity/")) AS ?property)\
    } ORDER BY ?property LIMIT 300';
    var wcqsEndpoint = 'https://wcqs-beta.wmflabs.org/sparql';
    var wcqsMoreLinkTemplate = 'https://wcqs-beta.wmflabs.org/#%23defaultView%3AImageGrid%0A%0ASELECT%20%3Ffile%20%3Fimage%0A%7B%0A%20%20hint%3AQuery%20hint%3Aoptimizer%20%22None%22.%0A%20%20%3Fstatement%20%3Fvalpred%20wd%3A%entityid%%20.%0A%20%20%3Fsubject%20%3Fclaimpred%20%3Fstatement%20.%0A%20%20%3Fsubject%20schema%3AcontentUrl%20%3Furl%20.%0A%20%20BIND%28IRI%28CONCAT%28%22http%3A%2F%2Fcommons.wikimedia.org%2Fwiki%2FSpecial%3AFilePath%2F%22%2C%20wikibase%3AdecodeUri%28SUBSTR%28STR%28%3Furl%29%2C53%29%29%29%29%20AS%20%3Fimage%29%0A%7D%0ALIMIT%201000';

    var htmlTemplate = '\
        <div id="%id%" style="clear: both;">\
        	<span class="oo-ui-widget oo-ui-widget-enabled oo-ui-buttonElement oo-ui-buttonElement-framed oo-ui-labelElement oo-ui-buttonWidget">\
            	<a class="wikibase-showinverse-button oo-ui-buttonElement-button"><span class="oo-ui-labelElement-label">%button%</span></a>\
            </span>\
            <h2 class="inverseclaims-header" class="wb-section-heading section-heading wikibase-statements" dir="auto" style="display:none;">\
                <span class="mw-headline">%title%</span>\
                <a href="%sparql%" target="_blank" style="font-size:small" class="inverseclaims-sparql">(SPARQL)</a>\
            </h2>\
            <div class="wikibase-statementgrouplistview">\
                <div class="wikibase-listview"></div>\
                <div class="wikibase-showinverse-status"></div>\
            </div>\
        </div>';
    
    function format(template, replacements) {
        for (var k in replacements) {
            template = template.replace(k, replacements[k]);
        }
        return template;
    }

    function loaditems(id, sparqlEndpoint, queryTemplate, moreLinkTemplate) {
        var root = $('#' + id);
        root.find('.wikibase-showinverse-button').hide();
        root.find('.inverseclaims-header').show();
        root.find('.wikibase-showinverse-status').html(messages.loading);
        var api = new mw.Api({
            ajax: {
                url: sparqlEndpoint + '?',
                dataType: 'json',
                cache: true
            }
        });
        api.get({
            query: format(queryTemplate, {"%entityid%": entityid, "%lang%": lang})
        }).done(function (data) {
            var stid = false;
            for (var k in data.results.bindings) {
                var page = data.results.bindings[k];
                var rank = page.rank.value.replace('http://wikiba.se/ontology#', '').replace('Rank', '').toLowerCase();
                var pid = page.property.value.replace('http://www.wikidata.org/entity/', 'i');
                if (pid != stid) {
                    var statementgroup = '\
                            <div id="' + pid + '" class="wikibase-statementgroupview listview-item"> \
                                <div class="wikibase-statementgroupview-property"> \
                                    <div class="wikibase-statementgroupview-property-label" dir="auto"> \
                                        <a href="' + page.property.value.replace('http://www.wikidata.org/entity/', 'https://www.wikidata.org/wiki/Property:') + '">' + page.inversepropertyLabel.value + '</a> \
                                    </div> \
                                </div> \
                                <div class="wikibase-statementlistview"> \
                                    <div class="wikibase-statementlistview-listview"> \
                                    </div> \
                                </div> \
                            </div>';
                    root.find('.wikibase-listview').append(statementgroup);
                    stid = pid;
                }
                var statement = '<div class="wikibase-statementview wb-normal listview-item wikibase-toolbar-item"> \
                    <div class="wikibase-statementview-rankselector"><div class="wikibase-rankselector ui-state-disabled"> \
                        <span class="ui-icon ui-icon-rankselector wikibase-rankselector-' + rank + '"></span> \
                    </div></div>  \
                    <div class="wikibase-statementview-mainsnak-container"> \
                        <div class="wikibase-statementview-mainsnak" dir="auto"> \
                            <div class="wikibase-snakview"> \
                                <div class="wikibase-snakview-property-container"> \
                                    <div class="wikibase-snakview-property" dir="auto"> \
                                    </div> \
                                </div> \
                                <div class="wikibase-snakview-value-container" dir="auto"> \
                                    <div class="wikibase-snakview-value wikibase-snakview-variation-valuesnak"> \
                                        <a href="' + page.subject.value.replace('http://www.wikidata.org/entity/', 'https://www.wikidata.org/wiki/') + '">' + page.subjectLabel.value + '</a>\
                                    </div> \
                                </div> \
                            </div> \
                        </div> \
                    </div> \
                </div>';
                $('.wikibase-statementgroupview').last().find('.wikibase-statementlistview-listview').append(statement);
            }
            if (data.results.bindings.length == 300) {
                var moreLink = format(moreLinkTemplate, {'%entityid%': entityid});
                root.find('.wikibase-showinverse-status').html('<a href="' + moreLink + '">' + messages.more + '</a>');
            } else if (data.results.bindings.length === 0) {
                root.find('.wikibase-showinverse-status').html(messages['no-result']);
            } else {
                root.find('.wikibase-showinverse-status').html('');
            }
        });
    }
    function init(mode, label, sparqlEndpoint, template, moreLinkTemplate) {
        var id = 'inverse-section-' + mode;
        var sparqlLink = format(moreLinkTemplate, {'%entityid%': entityid});
        var html = format(htmlTemplate, {'%id%': id, '%button%': label, '%title%': messages.title, '%sparql%': sparqlLink});

        $('.wikibase-entityview-main').append(html);
        $('#' + id).find('.wikibase-showinverse-button').click(function(event) {
            event.preventDefault();
            loaditems(id, sparqlEndpoint, template, moreLinkTemplate);
        });
    }

    $(function() {
        init('wd', messages['show-inverse'], wdEndpoint, wdTemplate, wdMoreLinkTemplate);
        init('wcqs', messages['show-inverse-commons'], wcqsEndpoint, wcqsTemplate, wcqsMoreLinkTemplate);
    });

}(mediaWiki, jQuery, wikibase));