User:MichaelSchoenitzer/quickpresets beta.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.
( function( wb, dv, mw, $ ) {
    // Implement str.format()
    if (!String.prototype.format) {
      String.prototype.format = function() {
        var args = arguments;
        return this.replace(/{(\d+)}/g, function(match, number) { 
          return typeof args[number] != 'undefined'
            ? args[number]
            : match
          ;
        });
      };
    }

    var interfacelang;

    var translatable_strings = {
        "Add {0}:": {
            "de": "{0} hinzufügen:"
        },
        "<p>Added {0} {1}</p>": {
            "de": "{0} {1} hinzugefügt"
        },
        "<p>Added {0} \"{1}\"</p>": {
            "de": "{0} \"{1}\" hinzugefügt"
        }
    };
    function _(string, ...args) {
        if(!(string in translatable_strings))
            var dest = string;
        else if(!(interfacelang in translatable_strings[string]))
            var dest = string;
        else
            var dest = translatable_strings[string][interfacelang];

        return dest.format(...args);
    }

    function Quickpresets() {
        this.config = null;
    }

    Quickpresets.prototype.init = function(configPage, lang) {
        var self = this;
        /**
         * Check if we're viewing an item
         */
        var qid = mw.config.get( 'wbEntityId' );
        if ( !qid ) {
            return;
        }

        if(typeof(lang) === "undefined")
            interfacelang = mw.config.get( 'wgUserLanguage' );
        else
            interfacelang = lang;

        importStylesheet( 'User:MichaelSchoenitzer/quickpresets.css' );
        if (typeof(configPage) === "undefined") {
            configPage = "User:"+mw.config.get("wgUserName")+"/quickpresets settings.json";
        }
        else {
            configPage = encodeURIComponent(configPage);
        }
        var configUrl = "https://www.wikidata.org/w/index.php?title=" + configPage +
                        "&action=raw&ctype=text/json";
        this.getConfig(configUrl, true).done(function(config) {
            self.config = config;
            /**
             * check if item is a of right kind
             */
            for( var t = 0; t<config.length; t++) {
                self.checktype(qid, config[t]);
            }
        });
    };


    Quickpresets.prototype.getConfig = function(configUrl, failback, dfd=$.Deferred()) {
        var self = this;
        $.ajax({
            url: configUrl,
            dataType: 'json',
            success: function( config ) {
                dfd.resolve(config);
            },
            error: function( result ) {
                if (failback) {
                    configUrl = "https://www.wikidata.org/w/index.php?title=" + 
                                "User:MichaelSchoenitzer/quickpresets_defaultconf.json" + 
                                "&action=raw&ctype=text/json";
                    self.getConfig(configUrl, false, dfd);
                }
                else {
                    console.log( 'Fatal Error loading quickpresets config' );
                }
            }
        });
        return dfd.promise();
    };

    /**
     * Load the entityselector-plugin, try until it works
     * See: https://stackoverflow.com/questions/47985370/
     */
    Quickpresets.prototype.loadentityselector = function() {
        try {
            $( ".quickpresetsiteminput input" ).entityselector( {
                url: 'https://www.wikidata.org/w/api.php',
                language: interfacelang
            } );
        }
        catch(err) {
            setTimeout(this.loadentityselector, 100);
        }
    };

    /**
     * Add the interface wich alows to quickly add statements
     */
    Quickpresets.prototype.addinterface = function(qid, prop) {
        var self = this;
        // compose and intert fieldset.
        var $fieldset = $("<fieldset id=\"quickpresets\">")
            .append($("<legend>")
                .text("Quick Presets ({0})".format(prop.name))
                .append("<a class='qpconfiglink' href='/wiki/Special:ConfigQuickpresets'>⚙</a>")
            )
            .insertAfter($('.wikibase-statementgrouplistview').first());

        prop.defaults.forEach(function(dflt) {
            if(typeof dflt.type == "undefined") {
                dflt.type = "item";
            }
            var $line = $("<div>").append(
                $("<p class='addstatement'>")
                .text(_("Add {0}:", dflt.name))
                .append("<span class='links'></span>")
                .append(
                   $("<span>")
                    .addClass("quickpresets" + dflt.type + "input")
                    .append("&nbsp;<input/>&nbsp;<a href=\'#\'>✔</a>")
                )
            ).appendTo($fieldset);
            if($('#'+dflt.pid).find(".wikibase-snakview-value a").length !== 0) {
                $line.addClass('disabled');
            }
            if(dflt.values.length === 0) {
                $line.addClass('compact');
            }
            $line.find('.quickpresets' + dflt.type + 'input a')
                .on('click', function(e) {
                    e.preventDefault();
                    if(dflt.type == "item") {
                        var selection = $(this).prev('input').data('entityselector').selectedEntity();
                        self.additemstatement(qid, dflt.pid, dflt.name, selection.id, selection.label);
                    }
                    else if(dflt.type == "string") {
                        self.addstringstatement(qid, dflt.pid, dflt.name, $(this).prev('input')[0].value);
                    }
                });

            // Add links for all preset-values…
            dflt.values.forEach(function(val) {
                $("<span>&nbsp;<a href='#'></a>&nbsp;∙</span>")
                    .appendTo($line.find('span.links'))
                    .find('a')
                    .text(val.name)
                    .on('click', function(e) {
                        e.preventDefault();
                        if(dflt.type == "item") {
                            self.additemstatement(qid, dflt.pid, dflt.name, val.qid, val.name);
                        }
                        else if(dflt.type == "string") {
                            self.addstringstatement(qid, dflt.pid, dflt.name, val.text);
                        }
                    });
            });

        });

        setTimeout(this.loadentityselector, 100);
    };

    /**
     * Add a formated claim and in case of success show succtext
     */
    Quickpresets.prototype.addclaim = function(claim, succtext) {
        var api = new mw.Api();
        var token = mw.user.tokens.values.csrfToken;
        api.post( { 
            action: 'wbsetclaim',
            summary: "Added with [[User:MichaelSchoenitzer/quickpresets|Quickpresets]]",
            claim: JSON.stringify(claim),
            token: token
        }).then(
            function(aw){
                if(aw.success == 1)
                    $('.wikibase-statementgrouplistview').first().after( succtext );
            }); 
    };

    /**
     * Add a statement with datatype 'item'
     * qid: the qid of the item wich should get the statment
     * pid: the property to add
     * pname: the name of the property for showing a success-note
     * toqid: the qid of the item that is used as value
     * toname: the name of the value-item property for showing a success-note
     */
    Quickpresets.prototype.additemstatement = function(qid, pid, pname, toqid, toname) {
        var self = this;
        var claim = {
            id: (new wb.utilities.ClaimGuidGenerator(qid)).newGuid(),
            type: "claim",
            mainsnak: {
                snaktype: "value",
                property: pid,
                datavalue: {
                    value: {
                        "entity-type": "item",
                        "numeric-id": toqid.substr(1)
                    },
                    type: "wikibase-entityid"
                },
                datatype: "wikibase-item"
            }
        };
        self.addclaim(claim, _("<p>Added {0} {1}</p>", pname, toname));
        // Check if we now support it with another element of the config
        if(pid == "P31") {
            $('#quickpresets').remove();
            for( var t = 0; t<self.config.length; t++) {
                if(self.config[t].qid == toqid) {
                    self.addinterface(qid, self.config[t]);
                }
            }
        }
    };

    /**
     * Add a statement with datatype 'string'
     * qid: the qid of the item wich should get the statment
     * pid: the property to add
     * pname: the name of the property for showing a success-note
     * str: the value of the statement
     */
    Quickpresets.prototype.addstringstatement = function(qid, pid, pname, str) {
        var self = this;
        var claim = {
            id: (new wb.utilities.ClaimGuidGenerator(qid)).newGuid(),
            type: "claim",
            mainsnak: {
                snaktype: "value",
                property: pid,
                datatype: "string",
                datavalue: {
                    value: str,
                    type: "string"
                }
            }
        };
        self.addclaim(claim, _("<p>Added {0} \"{1}\"</p>", pname, str));
    };

    /**
     * check if an item is of a type, if so add options
     */
    Quickpresets.prototype.checktype = function(qid, prop) {
        var self = this;
        var typeqid=prop.qid;
        // Search in HTML-DOM
        var typefromdom=$.map($('#P31').find(".wikibase-snakview-value a"),
            function(value, index) {
                if(typeof value.attributes.href === "undefined")
                    return [];
                else
                    return [value.attributes.href.value.substring(6)];
        });
        if ( typefromdom.length === 0) {
            if(typeqid === null)
                self.addinterface(qid, prop);
        }
        else {
            if ( typeqid === 0 ) {
                self.addinterface(qid, prop);
            }
            else if ( typefromdom.includes(typeqid) ) {
                self.addinterface(qid, prop);
            }
            else {
                // Now check via sparql (much slower but includes subtypes)
                const endpointUrl = 'https://query.wikidata.org/sparql',
                      sparqlQuery = 'Ask { wd:{0} wdt:P31/wdt:P279* wd:{1}. '.format(qid, typeqid) +
                                    'hint:Prior hint:gearing "forwards" }',
                      fullUrl = endpointUrl + '?query=' + encodeURIComponent( sparqlQuery ),
                      headers = { 'Accept': 'application/sparql-results+json' };
                fetch( fullUrl, { headers } ).then( body => body.json() ).then( json => {
                    if ( json.boolean )
                        self.addinterface(qid, prop);
                } );
            }
        }
    };

    wb.Quickpresets = Quickpresets;

}( wikibase, dataValues, mediaWiki, jQuery ) );