User:Tpt/ws2wd.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)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Press Ctrl-F5.
mw.loader.using(['mediawiki.widgets', 'mediawiki.util', 'mediawiki.api', 'oojs-ui-core' ], function () {
    $(function () {
        var wdApi = new mw.Api();

        function executeEntityQuery(sparqlWhere) {
            var sparql = 'SELECT ?entity ?entityLabel WHERE {' + sparqlWhere + ' SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en". } }';
            return $.ajax({
                url: 'https://query.wikidata.org/sparql',
                data: {
                    query: sparql,
                    format: 'json'
                },
                dataType: 'json'
            }).then(function (result) {
                return result.results.bindings.map(function (binding) {
                    return $('<a>').attr('href', binding.entity.value).text(binding.entityLabel.value);
                });
            }, function (jqXHR, textStatus) {
                OO.ui.alert('Convertion to SPARQL query failed: ' + JSON.stringify(textStatus));
            });
        }

        function itemClaim(propertyId, itemId) {
            return {
                mainsnak: {
                    snaktype: 'value',
                    property: propertyId,
                    datavalue: {
                        value: {
                            id: itemId
                        },
                        type: 'wikibase-entityid'
                    },
                    datatype: 'wikibase-item'
                },
                type: 'statement',
                rank: 'normal'
            };
        }

        function extractNewClaims(claims) {
            return claims.map(function (claim) {
                return {
                	mainsnak: claim.mainsnak,
                	qualifiers: claim.qualifiers || {},
                	type: claim.type,
                	rank: claim.rank
            	};
            });
        }

        function createWork(item) {
            executeEntityQuery('{ wd:' + item.id + ' wdt:P629+ ?entity . }').done(function (results) {
                if (results.length > 0) {
                    OO.ui.alert($('<span>').text('There is already a work item: ').append(results));
                } else {
                    postEntity({
                        type: 'item',
                        labels: {},
                        descriptions: {},
                        claims: {
                            P31: [itemClaim('P31', 'Q47461344')],
                            P50: extractNewClaims(item.claims.P50 || []),
                            P747: [itemClaim('P747', item.id)],
                        }
                    }).then(function (result) {
                        if ('entity' in result && 'id' in result.entity) {
                            addItemIdStatement(item.id, 'P629', result.entity.id).then(function () {
                            	mw.notify('Work item created');
                            	window.open('https://www.wikidata.org/entity/' + result.entity.id, '_blank');
                            }, function (jqXHR, textStatus) {
                                OO.ui.alert('Addition of the "edition of" statement failed: ' + JSON.stringify(textStatus));
                            });
                        } else {
                            OO.ui.alert('Entity saving done with unexpected result ' + JSON.stringify(result));
                        }
                    }, function (jqXHR, textStatus) {
                        OO.ui.alert('Creation of the work item failed: ' + JSON.stringify(textStatus));
                    });
                }
            });
        }
        
        function addItemIdStatement(subjectId, propertyId, objectId, qualifiers) {
        	return wdApi.postWithEditToken({
                action: 'wbcreateclaim',
                entity: subjectId,
                snaktype: 'value',
                property: propertyId,
                value: JSON.stringify({'id': objectId})
            }).then(function(result) {
            	if(result.claim && result.claim.id) {
            		mw.notify('Link from the work to this edition item created');
            		return $.when((qualifiers || []).map(function(qualifier) {
            			return wdApi.postWithEditToken({
	            			action: 'wbsetqualifier',
    	            		claim: result.claim.id,
        	    			snaktype: 'value',
            	    		property: qualifier.prop,
                			value: JSON.stringify(qualifier.value)
            			});
            		}));
            	} else {
            		OO.ui.alert('The saving of the edition claim failed with result: "' + JSON.stringify(result));
            		return $.Deferred().reject();
            	}
            });
        }
        
        function addEditionPropertyToWork(editionItem) {
        	return $.when((editionItem.claims.P629 || []).map(function(statement) {
        		if(statement.mainsnak.datavalue && statement.mainsnak.datavalue.value.id) {
        			return getEntity(statement.mainsnak.datavalue.value.id).then(function(workItem) {
        				if(!(workItem.claims.P747 || []).some(function(statement) {
        					return statement.mainsnak.datavalue && statement.mainsnak.datavalue.value.id == editionItem.id;
        				})) {
        					var qualifiers = [];
                        	if(editionItem.claims.P407) {
                        		editionItem.claims.P407.forEach(function(statement) {
                        			if(statement.mainsnak.datavalue && statement.mainsnak.datavalue.value) {
                        				qualifiers.push({prop: 'P407', value: statement.mainsnak.datavalue.value});
                        			}
                        		});
                        	}
        					return addItemIdStatement(workItem.id, 'P747', editionItem.id, qualifiers);
        				} else {
        					return $.when();
        				}
        			});
        		} else {
        			return $.when();
        		}
        	}));
        }

        function convertPage(title) {
            return $.ajax({
                url: 'https://tools.wmflabs.org/tptools/ws2wd.php',
                data: {
                    title: title
                },
                dataType: 'json'
            }).fail(function (jqXHR, textStatus) {
                OO.ui.alert('Convertion to Wikidata failed: ' + JSON.stringify(textStatus));
            });
        }

		function getEntity(entityId) {
            return wdApi.get({
                action: 'wbgetentities',
                ids: entityId
            }).then(function(content) {
            	if(entityId in content.entities) {
            		return content.entities[entityId];
            	} else {
            		OO.ui.alert('The Wikidata item ' + entityId + ' does not exists.');
            		return $.Deferred().reject(content);
            	}
            }, function (jqXHR, textStatus) {
                OO.ui.alert('Retrieval of the Wikidata item ' + entityId + ' failed: ' + JSON.stringify(textStatus));
            });
        }
        
        function postEntity(entity) {
            if ('id' in entity) {
                return wdApi.postWithEditToken({
                    action: 'wbeditentity',
                    id: entity.id,
                    data: JSON.stringify(entity)
                });
            } else {
                return wdApi.postWithEditToken({
                    action: 'wbeditentity',
                    new: entity.type,
                    data: JSON.stringify(entity)
                });
            }
        }

        function addFastImportationButton() {
            var $sitelinkElement = $('[data-wb-siteid="frwikisource"]');
            var title = $sitelinkElement.find('.wikibase-sitelinkview-page a').attr('title');
            if (title !== undefined) {
                $sitelinkElement.prepend(
                    $('<a>')
                        .append(new OO.ui.IconWidget({
                            icon: 'download',
                            iconTitle: 'Import microdata'
                        }).$element)
                        .css('float', 'right')
                        .click(function () {
                            doImportation(title);
                        })
                );
            }
        }

        function doImportation(title) {
            return new OO.ui.Process(convertPage(title.toString()).done(function (item) {
                return postEntity(item).then(function (result) {
                    if ('entity' in result && 'id' in result.entity) {
                    	 addEditionPropertyToWork(result.entity).done(function() {
                    	 	 setTimeout(function() {
	                    	 	window.location.href = 'https://www.wikidata.org/entity/' + result.entity.id;
                    	 	 }, 3000); //TODO: bad hack
                    	 });
                    } else {
                        OO.ui.alert('Entity saving done with result ' + JSON.stringify(result));
                    }
                }, function (jqXHR, textStatus) {
                    OO.ui.alert('Importation to Wikidata failed: ' + JSON.stringify(textStatus));
                });
            }));
        }

        function WS2WDDialog(config) {
            WS2WDDialog.super.call(this, config);
        }

        OO.inheritClass(WS2WDDialog, OO.ui.ProcessDialog);
        WS2WDDialog.static.name = 'wd2ws';
        WS2WDDialog.static.title = 'Wikisource to Wikidata import tool';
        WS2WDDialog.static.size = 'large';
        WS2WDDialog.static.actions = [
            {action: 'import', label: 'Import', flags: ['primary', 'constructive']},
            {label: 'Cancel', flags: 'safe'}
        ];

        WS2WDDialog.prototype.initialize = function () {
            WS2WDDialog.super.prototype.initialize.apply(this, arguments);

            var pageInput = new mw.widgets.TitleInputWidget({
                api: new mw.ForeignApi('https://fr.wikisource.org/w/api.php')
            });
            this.page = pageInput;

            var fieldset = new OO.ui.FieldsetLayout({
                label: 'Page on French Wikisource to import'
            });
            fieldset.addItems([pageInput]);

            this.panel = new OO.ui.PanelLayout({
                padded: true,
                expanded: false
            });
            this.panel.$element.append(fieldset.$element);
            this.$body.append(this.panel.$element);

            // We prefill the input
            mw.hook('wikibase.entityPage.entityLoaded').add(function (entity) {
                if ('sitelinks' in entity && 'frwikisource' in entity.sitelinks) {
                    pageInput.setValue(entity.sitelinks.frwikisource.title);
                }
            });
        };

        WS2WDDialog.prototype.getActionProcess = function (action) {
            if (action === 'import') {
                var title = this.page.getMWTitle();
                if (title === null) {
                    OO.ui.alert('The provided page title "' + this.page.getValue() + '"is invalid!');
                } else {
                    return doImportation(title);
                }
            }
            return WS2WDDialog.super.prototype.getActionProcess.call(this, action);
        };

        WS2WDDialog.prototype.getBodyHeight = function () {
            return this.panel.$element.outerHeight(true);
        };

        var windowManager = new OO.ui.WindowManager();
        $('body').append(windowManager.$element);
        windowManager.addWindows([new WS2WDDialog()]);

        var portletLink = mw.util.addPortletLink('p-tb', '#', 'Import Wikisource page');
        $(portletLink).click(function () {
            windowManager.openWindow('wd2ws');
        });

        if (mw.config.get('wgNamespaceNumber') === 0) {
            var workPortletLink = mw.util.addPortletLink('p-tb', '#', 'Create work item');
            $(workPortletLink).click(function () {
                mw.hook('wikibase.entityPage.entityLoaded').add(createWork);
            });
        }

        addFastImportationButton();
    });
});