var citoidQidTypeMap = { "artwork": "Q838948", "audioRecording": "Q5057302", "bill": "Q686822", "blogPost": "Q17928402", "book": "Q571", "bookSection": "Q1980247", "case": "Q2334719", "computerProgram": "Q5057302", "conferencePaper": "Q23927052", "dictionaryEntry": "Q4423781", "document": "Q49848", "email": "Q9158", "encyclopediaArticle": "Q17329259", "film": "Q11424", "forumPost": "Q7216866", "hearing": "Q545861", "instantMessage": "Q30070565", "interview": "Q178651", "journalArticle": "Q191067", "letter": "Q133492", "magazineArticle": "Q191067", "manuscript": "Q87167", "map": "Q4006", "newspaperArticle": "Q191067", "patent": "Q253623", "podcast": "Q5057302", "presentation": "Q604733", "radioBroadcast": "Q1555508", "report": "Q10870555", "statute": "Q820655", "thesis": "Q1266946", "tvBroadcast": "Q21191270", "videoRecording": "Q30070675", "webpage": "Q36774" }; var typeProperty = "P31"; // Property to use for "instance of" or "type"; corresponds to field 'itemType' in citoid ( function ( $, mw ) { 'use strict'; function ReferenceItem( data ) { this.data = data; // Raw data from citoid this.display = {}; // Elements for displaying the item } function CitoidDialog( config ) { CitoidDialog.super.call( this, config ); } OO.inheritClass( CitoidDialog, OO.ui.Dialog ); CitoidDialog.static.name = 'citoidDialog'; CitoidDialog.static.title = 'Create new reference item'; CitoidDialog.static.citoidFormat = 'mediawiki-basefields'; CitoidDialog.prototype.initialize = function () { CitoidDialog.super.prototype.initialize.call( this ); this.items = []; // List of ReferenceItem objects this.content = new OO.ui.PanelLayout( { padded: true, expanded: false } ); this.content.$element.append( '

Press \'Esc\' to close.

' ); this.$body.append( this.content.$element ); this.lookupInput = new OO.ui.TextInputWidget( { placeholder: 'URL, DOI, PMC or Title' } ); this.lookupButton = new OO.ui.ButtonWidget( { label: 'Search' } ); this.lookupActionFieldLayout = new OO.ui.ActionFieldLayout( this.lookupInput, this.lookupButton, { align: 'top', label: 'Search' } ); // Error label this.$noticeLabel = $( '
' ).addClass( 'oo-ui-element-hidden' ).text( 'Unable to retrieve data from input; try changing your search?' ); this.content.$element.append( this.lookupActionFieldLayout.$element, this.$noticeLabel ); // Restbase URL this.fullRestbaseUrl = 'https://en.wikipedia.org/api/'; // API config for citoid service if using citoid behind Restbase this.serviceUrl = this.fullRestbaseUrl + 'rest_v1/data/citation/' + CitoidDialog.static.citoidFormat; this.serviceConfig = { ajax: { // Request content in user language from citoid service. Possible we should do English as well to get both in case they are different. headers: { 'accept-language': mw.config.get( 'wgUserLanguage' ) }, crossDomain: true, timeout: 30 * 1000, // 30 seconds type: 'GET' } }; this.lookupButton.connect( this, { click: 'onLookupButtonClick' } ); }; // Override the getBodyHeight() method to specify a custom height (or don't to use the automatically generated height) CitoidDialog.prototype.getBodyHeight = function () { return this.content.$element.outerHeight( true ); }; CitoidDialog.prototype.getSetupProcess = function ( data ) { data = data || {}; return CitoidDialog.super.prototype.getSetupProcess.call( this, data ) .next( function () { // Set up contents based on data this.lookupInput.setValue( data.search ); }, this ); }; CitoidDialog.prototype.displayNewItem = function ( data ) { this.item = new ReferenceItem( data[0] ); // Hardcode to only use first citation for the time being this.items.push( this.item ); // Add to list of items in dialog /* Display Elements */ // Item label this.item.display.label = new OO.ui.TextInputWidget( { value: this.item.data.title, label: 'label' } ); // Item description this.item.display.description = new OO.ui.TextInputWidget( { value: this.item.data.itemType, label: 'description' } ); // Button this.item.display.createButton = new OO.ui.ButtonWidget( { label: 'Create new item' } ); // Item creation failure message this.item.display.$failureLabel = $( '
' ) .addClass( 'oo-ui-element-hidden' ) .text( 'Unable to create new item; item with same label and description already exists. Try changing the description?' ); /* Actions */ this.item.display.createButton.connect( this, { click: 'onCreateButtonClick' } ); /* Layout */ this.item.display.itemLayout = new OO.ui.FieldsetLayout( { label: 'New Item', classes: ["container"] } ); this.item.display.itemLayout.addItems( [ new OO.ui.FieldLayout( this.item.display.label, { label: this.item.display.label.label, align: 'left' } ), new OO.ui.FieldLayout( this.item.display.description, { label: this.item.display.description.label, align: 'left' } ) ]); this.content.$element.append( this.item.display.itemLayout.$element, this.item.display.createButton.$element, this.item.display.$failureLabel ); this.updateSize(); }; /** * Handle click events from the lookup button, perform lookup */ CitoidDialog.prototype.onLookupButtonClick = function () { this.executeAction( 'lookup' ); }; /** * Handle click events from the lookup button, perform lookup */ CitoidDialog.prototype.onCreateButtonClick = function () { this.executeAction( 'create' ); }; CitoidDialog.prototype.getActionProcess = function ( action ) { var dialog = this; if ( action === 'lookup' ) { return new OO.ui.Process( function () { return this.performLookup().then( function ( data ) { dialog.displayNewItem( data ); }, // Failure function () { dialog.lookupFailed(); }); }, this ); } if ( action === 'create' ) { return new OO.ui.Process( function () { dialog.createNewItem(); }, this ); } // Fallback to parent handler return CitoidDialog.super.prototype.getActionProcess.call( this, action ); }; CitoidDialog.prototype.createNewItem = function ( ) { var dialog = this; var data = { labels:[ { language:"en", value: this.item.display.label.value } ], descriptions:[ { language:"en", value: this.item.display.description.value } ] }; var api = new mw.Api(); // Set as pending this.item.display.createButton.setDisabled( true ); this.item.display.label.setDisabled( true ).pushPending(); this.item.display.description.setDisabled( true ).pushPending(); api.postWithEditToken( { assert: 'user', action: 'wbeditentity', new: 'item', data: JSON.stringify(data), format: 'json' } ).then( function ( results ) { if ( results.success && results.success === 1 ) { dialog.insertItem( results ); } else { dialog.creationFailed(); } // Failure }, function ( ) { dialog.creationFailed(); } ); } CitoidDialog.prototype.insertItem = function ( results ) { this.close( results.entity.id ); // Remove pre-creation display //this.item.display.itemLayout.$element.remove(); //this.item.display.createButton.$element.remove(); // Update display //this.content.$element.append( '

Created new item ' + results.entity.id + '

' ); //this.updateSize(); // TODO insert item into field }; /** * Send a request to the citoid service * * @return {jQuery.Promise} Lookup promise */ CitoidDialog.prototype.performLookup = function () { var xhr, search, dialog = this; // Clear prior results this.clearResults(); // TODO: Add caching for requested urls if ( this.lookupPromise ) { // Abort existing lookup this.lookupPromise.abort(); this.lookupPromise = null; this.lookupInput.popPending(); } // Set as pending this.lookupButton.setDisabled( true ); this.lookupInput.setDisabled( true ).pushPending(); search = this.lookupInput.getValue(); search = decodeURIComponent( search ); // We have to first set up a get response so we can have // a proper xhr object with "abort" method, so we can // hand off this abort method to the jquery promise if ( this.fullRestbaseUrl ) { // Use restbase endpoint this.serviceConfig.ajax.url = this.serviceUrl + '/' + encodeURIComponent( search ); xhr = new mw.Api( this.serviceConfig ).get(); } else { // Use standalone citoid service xhr = this.service .get( { search: search, format: ve.ui.CiteFromIdInspector.static.citoidFormat } ); } this.lookupPromise = xhr .always( function () { dialog .lookupInput .setDisabled( false ) // restore focus to the input field .focus() .popPending(); dialog.lookupButton.setDisabled( false ); } ) .promise( { abort: xhr.abort } ); return this.lookupPromise; }; CitoidDialog.prototype.lookupFailed = function () { // Enable the input and lookup button this.$noticeLabel.removeClass( 'oo-ui-element-hidden' ); this.lookupInput.once( 'change', function () { this.$noticeLabel.addClass( 'oo-ui-element-hidden' ); this.updateSize(); }.bind( this ) ).setValidityFlag( false ); this.updateSize(); }; CitoidDialog.prototype.creationFailed = function () { // Enable the input and lookup button this.item.display.$failureLabel.removeClass( 'oo-ui-element-hidden' ); this.item.display.label.setDisabled( false ).popPending(); this.item.display.description.setDisabled( false ).popPending(); this.item.display.createButton.setDisabled( false ); this.updateSize(); }; /** * Clear the search results */ CitoidDialog.prototype.clearResults = function () { var i; for (i = 0; i < this.items.length; i++) { this.item.display.itemLayout.$element.remove(); this.item.display.createButton.$element.remove(); this.item.display.$failureLabel.remove(); } this.items = []; this.updateSize(); }; // Make the window. var citoidDialog = new CitoidDialog( { size: 'medium' } ); // Create and append a window manager, which will open and close the window. var windowManager = new OO.ui.WindowManager(); $( 'body' ).append( windowManager.$element ); // Add the window to the window manager using the addWindows() method. windowManager.addWindows( [ citoidDialog ] ); function init() { var currentField = $( 'input' ); var willEntitySelectorListUpdate = false; $( document ).on( 'input propertychange paste', '.wikibase-snakview-value-container:has(.ui-suggester-input)', function () { currentField = $( this ).find( '.ui-suggester-input' ).first(); willEntitySelectorListUpdate = true; } ); $( document ).on( 'DOMSubtreeModified', '.ui-entityselector-list', function () { if ( willEntitySelectorListUpdate ) { var firstLi = $( this ).find( 'li' ).first(); var isNotFound = firstLi.hasClass( 'ui-entityselector-notfound' ); if ( isNotFound ) { willEntitySelectorListUpdate = false; var $innerA = firstLi.find( 'a' ).first(); $innerA.on( 'click', function () { firstLi.remove(); var citoidWindow = windowManager.openWindow( citoidDialog, { search: currentField.val() } ); citoidWindow.opened.then( function () { citoidDialog.executeAction( 'lookup' ); } ); citoidWindow.closed.then( function( qid ) { if ( qid ) { currentField.val( qid ); } } ); return false; } ); $innerA.text( "No item with that title found; Create new reference item?" ); } } } ); } $( function () { mw.hook( 'wikibase.entityPage.entityLoaded' ).add( init ); } ); }( jQuery, mediaWiki ) );