Adrian Lang has uploaded a new change for review. https://gerrit.wikimedia.org/r/199295
Change subject: Introduce wikibase.view.entityIdFormatter ...................................................................... Introduce wikibase.view.entityIdFormatter Change-Id: I4a2fdfbc3faa8a640683006111539812ab764faf --- M .jshintrc M lib/resources/jquery.wikibase/jquery.wikibase.referenceview.js M lib/resources/jquery.wikibase/jquery.wikibase.snaklistview.js M lib/resources/jquery.wikibase/jquery.wikibase.statementgrouplistview.js M lib/resources/jquery.wikibase/jquery.wikibase.statementgroupview.js M lib/resources/jquery.wikibase/jquery.wikibase.statementlistview.js M lib/resources/jquery.wikibase/jquery.wikibase.statementview.js M lib/resources/jquery.wikibase/resources.php M lib/resources/jquery.wikibase/snakview/resources.php M lib/resources/jquery.wikibase/snakview/snakview.js M lib/tests/qunit/jquery.wikibase/jquery.wikibase.itemview.tests.js M lib/tests/qunit/jquery.wikibase/jquery.wikibase.propertyview.tests.js M lib/tests/qunit/jquery.wikibase/jquery.wikibase.referenceview.tests.js M lib/tests/qunit/jquery.wikibase/jquery.wikibase.snaklistview.tests.js M lib/tests/qunit/jquery.wikibase/jquery.wikibase.statementgrouplistview.tests.js M lib/tests/qunit/jquery.wikibase/jquery.wikibase.statementgroupview.tests.js M lib/tests/qunit/jquery.wikibase/jquery.wikibase.statementlistview.tests.js M lib/tests/qunit/jquery.wikibase/jquery.wikibase.statementview.tests.js M lib/tests/qunit/jquery.wikibase/resources.php M lib/tests/qunit/jquery.wikibase/snakview/resources.php M lib/tests/qunit/jquery.wikibase/snakview/snakview.tests.js A view/resources/entityIdFormatter/EntityIdHtmlFormatter.js A view/resources/entityIdFormatter/EntityIdPlainFormatter.js A view/resources/entityIdFormatter/SimpleEntityIdHtmlFormatter.js A view/resources/entityIdFormatter/SimpleEntityIdPlainFormatter.js A view/resources/entityIdFormatter/namespace.js A view/resources/entityIdFormatter/resources.php M view/resources/resources.php A view/tests/qunit/entityIdFormatter/SimpleEntityIdHtmlFormatter.tests.js A view/tests/qunit/entityIdFormatter/SimpleEntityIdPlainFormatter.tests.js A view/tests/qunit/entityIdFormatter/resources.php A view/tests/qunit/entityIdFormatter/testEntityIdHtmlFormatter.js M view/tests/qunit/resources.php 33 files changed, 626 insertions(+), 125 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Wikibase refs/changes/95/199295/1 diff --git a/.jshintrc b/.jshintrc index 0d8273e..983f025 100644 --- a/.jshintrc +++ b/.jshintrc @@ -49,6 +49,11 @@ "globals": { "QUnit": false } + }, + "view/tests/qunit/entityIdFormatter/testEntityIdHtmlFormatter.js": { + "globals": { + "QUnit": false + } } } diff --git a/lib/resources/jquery.wikibase/jquery.wikibase.referenceview.js b/lib/resources/jquery.wikibase/jquery.wikibase.referenceview.js index cba1cd5..22aaa06 100644 --- a/lib/resources/jquery.wikibase/jquery.wikibase.referenceview.js +++ b/lib/resources/jquery.wikibase/jquery.wikibase.referenceview.js @@ -113,6 +113,8 @@ value: value || undefined, singleProperty: true, dataTypeStore: self.options.dataTypeStore, + entityIdHtmlFormatter: self.options.entityIdHtmlFormatter, + entityIdPlainFormatter: self.options.entityIdPlainFormatter, entityStore: self.options.entityStore, valueViewBuilder: self.options.valueViewBuilder }; diff --git a/lib/resources/jquery.wikibase/jquery.wikibase.snaklistview.js b/lib/resources/jquery.wikibase/jquery.wikibase.snaklistview.js index 7474e77..f18a515 100644 --- a/lib/resources/jquery.wikibase/jquery.wikibase.snaklistview.js +++ b/lib/resources/jquery.wikibase/jquery.wikibase.snaklistview.js @@ -160,6 +160,8 @@ property: !!value }, dataTypeStore: self.option( 'dataTypeStore' ), + entityIdHtmlFormatter: self.options.entityIdHtmlFormatter, + entityIdPlainFormatter: self.options.entityIdPlainFormatter, entityStore: self.option( 'entityStore' ), valueViewBuilder: self.option( 'valueViewBuilder' ) }; diff --git a/lib/resources/jquery.wikibase/jquery.wikibase.statementgrouplistview.js b/lib/resources/jquery.wikibase/jquery.wikibase.statementgrouplistview.js index 9fcf4c3..048a1f5 100644 --- a/lib/resources/jquery.wikibase/jquery.wikibase.statementgrouplistview.js +++ b/lib/resources/jquery.wikibase/jquery.wikibase.statementgrouplistview.js @@ -120,6 +120,12 @@ this.$listview = $( '<div/>' ).appendTo( this.element ); } + var entityIdHtmlFormatter = new wb.view.entityIdFormatter.SimpleEntityIdHtmlFormatter( + this.options.entityStore + ); + var entityIdPlainFormatter = new wb.view.entityIdFormatter.SimpleEntityIdPlainFormatter( + this.options.entityStore + ); this.$listview.listview( { listItemAdapter: new $.wikibase.listview.ListItemAdapter( { listItemWidget: $.wikibase.statementgroupview, @@ -129,6 +135,8 @@ claimGuidGenerator: self.options.claimGuidGenerator, entityType: self.options.entityType, dataTypeStore: self.options.dataTypeStore, + entityIdHtmlFormatter: entityIdHtmlFormatter, + entityIdPlainFormatter: entityIdPlainFormatter, entityStore: self.options.entityStore, valueViewBuilder: self.options.valueViewBuilder, entityChangersFactory: self.options.entityChangersFactory diff --git a/lib/resources/jquery.wikibase/jquery.wikibase.statementgroupview.js b/lib/resources/jquery.wikibase/jquery.wikibase.statementgroupview.js index 39396ed..8a7c016 100644 --- a/lib/resources/jquery.wikibase/jquery.wikibase.statementgroupview.js +++ b/lib/resources/jquery.wikibase/jquery.wikibase.statementgroupview.js @@ -29,6 +29,8 @@ * Type of the entity that the widget refers to. * @param {wikibase.store.EntityStore} options.entityStore * Required for dynamically gathering `Entity`/`Property` information. + * @param {wikibase.view.entityIdFormatter.EntityIdHtmlFormatter} options.entityIdHtmlFormatter + * Required for dynamically rendering links to entities. * @param {wikibase.ValueViewBuilder} options.valueViewBuilder * Required by the `snakview` interfacing a `snakview` "value" `Variation` to * `jQuery.valueview`. @@ -63,6 +65,7 @@ }, value: null, claimGuidGenerator: null, + entityIdHtmlFormatter: null, entityType: wb.datamodel.Item.TYPE, entityStore: null, valueViewBuilder: null, @@ -84,6 +87,7 @@ _create: function() { if( !this.options.claimGuidGenerator + || !this.options.entityIdHtmlFormatter || !this.options.entityStore || !this.options.valueViewBuilder || !this.options.entityChangersFactory @@ -128,22 +132,8 @@ var self = this, propertyId = this.options.value.getKey(); - this.options.entityStore.get( propertyId ).done( function( property ) { - var $title; - - if( property ) { - $title = wb.utilities.ui.buildLinkToEntityPage( - property.getContent(), - property.getTitle() - ); - } else { - $title = wb.utilities.ui.buildMissingEntityInfo( - propertyId, - wb.datamodel.Property - ); - } - - self.$propertyLabel.append( $title ); + this.options.entityIdHtmlFormatter.format( propertyId ).done( function( title ) { + self.$propertyLabel.append( title ); } ); }, @@ -173,6 +163,8 @@ ? this.options.value.getItemContainer() : new wb.datamodel.StatementList(), claimGuidGenerator: self.options.claimGuidGenerator, + entityIdHtmlFormatter: self.options.entityIdHtmlFormatter, + entityIdPlainFormatter: self.options.entityIdPlainFormatter, entityType: self.options.entityType, entityStore: self.options.entityStore, valueViewBuilder: self.options.valueViewBuilder, diff --git a/lib/resources/jquery.wikibase/jquery.wikibase.statementlistview.js b/lib/resources/jquery.wikibase/jquery.wikibase.statementlistview.js index bf9aefd..a700076 100644 --- a/lib/resources/jquery.wikibase/jquery.wikibase.statementlistview.js +++ b/lib/resources/jquery.wikibase/jquery.wikibase.statementlistview.js @@ -190,6 +190,8 @@ } }, dataTypeStore: self.option( 'dataTypeStore' ), + entityIdHtmlFormatter: self.options.entityIdHtmlFormatter, + entityIdPlainFormatter: self.options.entityIdPlainFormatter, entityStore: self.option( 'entityStore' ), valueViewBuilder: self.option( 'valueViewBuilder' ), entityChangersFactory: self.option( 'entityChangersFactory' ), diff --git a/lib/resources/jquery.wikibase/jquery.wikibase.statementview.js b/lib/resources/jquery.wikibase/jquery.wikibase.statementview.js index 72f1435..737dee7 100644 --- a/lib/resources/jquery.wikibase/jquery.wikibase.statementview.js +++ b/lib/resources/jquery.wikibase/jquery.wikibase.statementview.js @@ -226,6 +226,8 @@ locked: this.options.locked.mainSnak, autoStartEditing: false, dataTypeStore: this.options.dataTypeStore, + entityIdHtmlFormatter: this.options.entityIdHtmlFormatter, + entityIdPlainFormatter: this.options.entityIdPlainFormatter, entityStore: this.options.entityStore, valueViewBuilder: this.options.valueViewBuilder, encapsulatedBy: ':' + this.widgetFullName.toLowerCase() @@ -270,6 +272,8 @@ value: value || undefined, singleProperty: true, dataTypeStore: self.options.dataTypeStore, + entityIdHtmlFormatter: self.options.entityIdHtmlFormatter, + entityIdPlainFormatter: self.options.entityIdPlainFormatter, entityStore: self.options.entityStore, valueViewBuilder: self.options.valueViewBuilder }; @@ -334,6 +338,8 @@ value: value || null, statementGuid: self.options.value.getClaim().getGuid(), dataTypeStore: self.options.dataTypeStore, + entityIdHtmlFormatter: self.options.entityIdHtmlFormatter, + entityIdPlainFormatter: self.options.entityIdPlainFormatter, entityStore: self.options.entityStore, valueViewBuilder: self.options.valueViewBuilder, referencesChanger: self._referencesChanger @@ -422,14 +428,8 @@ this.options.helpMessage = deferred.promise(); if( property ) { - this.options.entityStore.get( property ).done( function( fetchedProperty ) { - if( fetchedProperty ) { - helpMessage = mw.msg( - 'wikibase-claimview-snak-tooltip', - wb.utilities.ui.buildPrettyEntityLabelText( fetchedProperty.getContent() ) - ); - } - deferred.resolve( helpMessage ); + this.options.entityIdPlainFormatter.format( property ).done( function( formattedEntityId ) { + deferred.resolve( mw.msg( 'wikibase-claimview-snak-tooltip', formattedEntityId ) ); } ); } else { deferred.resolve( helpMessage ); diff --git a/lib/resources/jquery.wikibase/resources.php b/lib/resources/jquery.wikibase/resources.php index e17ae2d..3a85359 100644 --- a/lib/resources/jquery.wikibase/resources.php +++ b/lib/resources/jquery.wikibase/resources.php @@ -71,6 +71,7 @@ 'jquery.wikibase.listview', 'wikibase.datamodel.Item', 'wikibase.datamodel.StatementGroupSet', + 'wikibase.view.entityIdFormatter.SimpleEntityIdHtmlFormatter', ), ), @@ -87,7 +88,7 @@ 'wikibase.datamodel.Property', 'wikibase.datamodel.StatementGroup', 'wikibase.datamodel.StatementList', - 'wikibase.utilities', + 'wikibase.utilities.ClaimGuidGenerator', ), ), @@ -356,7 +357,6 @@ 'mediawiki.jqueryMsg', // for {{plural}} and {{gender}} support in messages 'wikibase.buildErrorOutput', 'wikibase.sites', - 'wikibase.utilities', ), ), diff --git a/lib/resources/jquery.wikibase/snakview/resources.php b/lib/resources/jquery.wikibase/snakview/resources.php index f6f391b..5328ec0 100644 --- a/lib/resources/jquery.wikibase/snakview/resources.php +++ b/lib/resources/jquery.wikibase/snakview/resources.php @@ -40,7 +40,6 @@ 'wikibase.datamodel', 'wikibase.serialization.SnakDeserializer', 'wikibase.serialization.SnakSerializer', - 'wikibase.utilities', ), 'messages' => array( 'wikibase-snakview-property-input-placeholder', diff --git a/lib/resources/jquery.wikibase/snakview/snakview.js b/lib/resources/jquery.wikibase/snakview/snakview.js index d4ceb37..eb4baa4 100644 --- a/lib/resources/jquery.wikibase/snakview/snakview.js +++ b/lib/resources/jquery.wikibase/snakview/snakview.js @@ -90,6 +90,8 @@ snaktype: false }, autoStartEditing: true, + entityIdPlainFormatter: null, + entityIdHtmlFormatter: null, entityStore: null, valueViewBuilder: null, dataTypeStore: null, @@ -753,66 +755,56 @@ */ _getPropertyDOM: function( propertyId ) { var self = this, - deferred = $.Deferred(); + deferred = $.Deferred(), + editable = !this.options.locked.property && this.isInEditMode(); - if( propertyId ) { - this.options.entityStore.get( propertyId ) - .done( function( fetchedProperty ) { - deferred.resolve( self._createPropertyDOM( - fetchedProperty ? fetchedProperty.getContent() : undefined, - fetchedProperty ? fetchedProperty.getTitle() : undefined - ) ); - } ) - .fail( deferred.reject ); + if( !propertyId ) { + if( editable ) { + deferred.resolve( this._createPropertyDOM( '' ) ); + } else { + deferred.resolve( '' ); + } } else { - deferred.resolve( this._createPropertyDOM() ); + if( editable ) { + this.options.entityIdPlainFormatter.format( propertyId ).done( function( propertyLabel ) { + deferred.resolve( self._createPropertyDOM( propertyLabel ) ); + } ); + } else { + // Property is set already and cannot be changed, display label only: + return this.options.entityIdHtmlFormatter.format( propertyId ); + } } - return deferred.promise(); }, /** - * Creates the DOM structure specific for a `Property`-`Title` combination, a generic DOM - * structure or an input element if parameters are omitted. + * Creates the DOM structure specific for a `Property`, a generic DOM + * structure or an input element. * @private * - * @param {wikibase.datamodel.Property} [property] `Property` object or `Property` id. Returns - * generic DOM structure if omitted. - * @param {mediawiki.Title} [title] - * @return {jQuery} + * @param {string} propertyLabel Rendered label for the `Property` + * @return {jQuery|null} */ - _createPropertyDOM: function( property, title ) { + _createPropertyDOM: function( propertyLabel ) { var $propertyDom; - if( this.options.locked.property || !this.isInEditMode() ) { - // Property is set already and cannot be changed, display label only: - $propertyDom = property instanceof wb.datamodel.Property - ? wb.utilities.ui.buildLinkToEntityPage( property, title ) - // shouldn't usually happen, only in non-edit mode, while no Snak is set: - : wb.utilities.ui.buildMissingEntityInfo( property, wb.datamodel.Property ); - } else { - // No Property set for this Snak, serve edit view to specify it: - var propertySelector = this._getPropertySelector(), - propertyLabel = property instanceof wb.datamodel.Property - ? wb.utilities.ui.buildPrettyEntityLabelText( property ) - : property; + // No Property set for this Snak, serve edit view to specify it: + var propertySelector = this._getPropertySelector(); - // TODO: use selectedEntity() or other command to set selected entity in both cases! - if( propertySelector ) { - // property selector in DOM already, just replace current value - var currentValue = propertySelector.widget().val(); - // Impose case-insensitivity: - if( propertyLabel.toLowerCase() !== currentValue.toLocaleLowerCase() ) { - propertySelector.widget().val( propertyLabel ); - } - } else { - $propertyDom = this._buildPropertySelector().val( propertyLabel ); - - // propagate snakview state: - $propertyDom.data( 'entityselector' ).option( 'disabled', this.options.disabled ); + // TODO: use selectedEntity() or other command to set selected entity in both cases! + if( propertySelector ) { + // property selector in DOM already, just replace current value + var currentValue = propertySelector.widget().val(); + // Impose case-insensitivity: + if( propertyLabel.toLowerCase() !== currentValue.toLocaleLowerCase() ) { + propertySelector.widget().val( propertyLabel ); } - } + } else { + $propertyDom = this._buildPropertySelector().val( propertyLabel ); + // propagate snakview state: + $propertyDom.data( 'entityselector' ).option( 'disabled', this.options.disabled ); + } return $propertyDom; }, diff --git a/lib/tests/qunit/jquery.wikibase/jquery.wikibase.itemview.tests.js b/lib/tests/qunit/jquery.wikibase/jquery.wikibase.itemview.tests.js index a4b8f9a..f89db4e 100644 --- a/lib/tests/qunit/jquery.wikibase/jquery.wikibase.itemview.tests.js +++ b/lib/tests/qunit/jquery.wikibase/jquery.wikibase.itemview.tests.js @@ -12,7 +12,7 @@ */ var createItemview = function( options, $node ) { options = $.extend( { - entityStore: 'I am an EntityStore', + entityStore: new wb.store.EntityStore(), entityChangersFactory: { getAliasesChanger: function() { return 'I am an AliasesChanger'; }, getDescriptionsChanger: function() { return 'I am a DescriptionsChanger'; }, diff --git a/lib/tests/qunit/jquery.wikibase/jquery.wikibase.propertyview.tests.js b/lib/tests/qunit/jquery.wikibase/jquery.wikibase.propertyview.tests.js index 3dcaa0a..05c789e 100644 --- a/lib/tests/qunit/jquery.wikibase/jquery.wikibase.propertyview.tests.js +++ b/lib/tests/qunit/jquery.wikibase/jquery.wikibase.propertyview.tests.js @@ -12,7 +12,7 @@ */ var createPropertyview = function( options, $node ) { options = $.extend( { - entityStore: 'I am an EntityStore', + entityStore: new wb.store.EntityStore(), entityChangersFactory: { getAliasesChanger: function() { return 'I am an AliasesChanger'; }, getDescriptionsChanger: function() { return 'I am a DescriptionsChanger'; }, diff --git a/lib/tests/qunit/jquery.wikibase/jquery.wikibase.referenceview.tests.js b/lib/tests/qunit/jquery.wikibase/jquery.wikibase.referenceview.tests.js index 0e982f8..a7b951f 100644 --- a/lib/tests/qunit/jquery.wikibase/jquery.wikibase.referenceview.tests.js +++ b/lib/tests/qunit/jquery.wikibase/jquery.wikibase.referenceview.tests.js @@ -1,26 +1,9 @@ /** * @licence GNU GPL v2+ - * @author Adrian Lang < adrian.l...@wikimedia.de > + * @author Adrian Heine < adrian.he...@wikimedia.de > */ -( function( $, mw, wb, vv, vf, QUnit ) { +( function( $, wb, vv, vf, QUnit ) { 'use strict'; - - // We need an entity store for the instances of jquery.wikibase.referenceview - // and jquery.wikibase.snakview created by jquery.wikibase.referenceview. - var entityStore = { - get: function() { - return $.Deferred().resolve( new wb.store.FetchedContent( { - title: new mw.Title( 'Property:P1' ), - content: new wb.datamodel.Property( - 'P1', - 'string', - new wb.datamodel.Fingerprint( new wb.datamodel.TermMap( [ - new wb.datamodel.Term( 'en', 'P1' ) - ] ) ) - ) - } ) ); - } - }; var valueViewBuilder = new wb.ValueViewBuilder( new vv.ExpertStore(), @@ -39,7 +22,17 @@ function createReferenceview( statementGuid, additionalOptions ) { var options = $.extend( additionalOptions, { statementGuid: statementGuid, - entityStore: entityStore, + entityIdHtmlFormatter: { + format: function() { + return $.Deferred().resolve( 'P1' ).promise(); + } + }, + entityIdPlainFormatter: { + format: function() { + return $.Deferred().resolve( 'P1' ).promise(); + } + }, + entityStore: 'I am an EntityStore', valueViewBuilder: valueViewBuilder, referencesChanger: 'i am a ReferencesChanger', dataTypeStore: 'I am a DataTypeStore' @@ -192,4 +185,4 @@ ); } ); -} )( jQuery, mediaWiki, wikibase, jQuery.valueview, valueFormatters, QUnit ); +} )( jQuery, wikibase, jQuery.valueview, valueFormatters, QUnit ); diff --git a/lib/tests/qunit/jquery.wikibase/jquery.wikibase.snaklistview.tests.js b/lib/tests/qunit/jquery.wikibase/jquery.wikibase.snaklistview.tests.js index 6cc4db2..21bf589 100644 --- a/lib/tests/qunit/jquery.wikibase/jquery.wikibase.snaklistview.tests.js +++ b/lib/tests/qunit/jquery.wikibase/jquery.wikibase.snaklistview.tests.js @@ -73,6 +73,16 @@ dataTypeStore: { getDataType: function() {} }, + entityIdHtmlFormatter: { + format: function() { + return $.Deferred().resolve( 'P1' ).promise(); + } + }, + entityIdPlainFormatter: { + format: function( entityId ) { + return $.Deferred().resolve( entityId ).promise(); + } + }, entityStore: entityStore, valueViewBuilder: valueViewBuilder } ); diff --git a/lib/tests/qunit/jquery.wikibase/jquery.wikibase.statementgrouplistview.tests.js b/lib/tests/qunit/jquery.wikibase/jquery.wikibase.statementgrouplistview.tests.js index d388e44..e9ebc0e 100644 --- a/lib/tests/qunit/jquery.wikibase/jquery.wikibase.statementgrouplistview.tests.js +++ b/lib/tests/qunit/jquery.wikibase/jquery.wikibase.statementgrouplistview.tests.js @@ -6,6 +6,11 @@ ( function( $, wb, QUnit ) { 'use strict'; +var entityStore = new wb.store.EntityStore(); +entityStore.get = function () { + return $.Deferred().resolve().promise(); +}; + /** * @param {Object} [options={}] * @param {jQuery} [$node] @@ -14,11 +19,7 @@ var createStatementgrouplistview = function( options, $node ) { options = $.extend( { claimGuidGenerator: 'I am a ClaimGuidGenerator', - entityStore: { - get: function () { - return $.Deferred().resolve().promise(); - } - }, + entityStore: entityStore, valueViewBuilder: 'i am a ValueViewBuilder', entityChangersFactory: { getClaimsChanger: function() { diff --git a/lib/tests/qunit/jquery.wikibase/jquery.wikibase.statementgroupview.tests.js b/lib/tests/qunit/jquery.wikibase/jquery.wikibase.statementgroupview.tests.js index b582c19..c04d6f6 100644 --- a/lib/tests/qunit/jquery.wikibase/jquery.wikibase.statementgroupview.tests.js +++ b/lib/tests/qunit/jquery.wikibase/jquery.wikibase.statementgroupview.tests.js @@ -18,6 +18,16 @@ return $.Deferred().resolve().promise(); } }, + entityIdHtmlFormatter: { + format: function ( entityId ) { + return $.Deferred().resolve( 'Link to entity' ).promise(); + } + }, + entityIdPlainFormatter: { + format: function ( entityId ) { + return $.Deferred().resolve( entityId ).promise(); + } + }, valueViewBuilder: 'I am a ValueViewBuilder', entityChangersFactory: { getClaimsChanger: function() { diff --git a/lib/tests/qunit/jquery.wikibase/jquery.wikibase.statementlistview.tests.js b/lib/tests/qunit/jquery.wikibase/jquery.wikibase.statementlistview.tests.js index a95189b..6594025 100644 --- a/lib/tests/qunit/jquery.wikibase/jquery.wikibase.statementlistview.tests.js +++ b/lib/tests/qunit/jquery.wikibase/jquery.wikibase.statementlistview.tests.js @@ -13,6 +13,11 @@ var createStatementlistview = function( options, $node ) { options = $.extend( { claimGuidGenerator: 'I am a ClaimGuidGenerator', + entityIdPlainFormatter: { + format: function ( entityId ) { + return $.Deferred().resolve( entityId ).promise(); + } + }, entityStore: { get: function () { return $.Deferred().resolve().promise(); diff --git a/lib/tests/qunit/jquery.wikibase/jquery.wikibase.statementview.tests.js b/lib/tests/qunit/jquery.wikibase/jquery.wikibase.statementview.tests.js index 412dc37..f96c7a6 100644 --- a/lib/tests/qunit/jquery.wikibase/jquery.wikibase.statementview.tests.js +++ b/lib/tests/qunit/jquery.wikibase/jquery.wikibase.statementview.tests.js @@ -43,6 +43,16 @@ var createStatementview = function( options, $node ) { options = $.extend( { entityStore: entityStore, + entityIdHtmlFormatter: { + format: function( entityId ) { + return $.Deferred().resolve( entityId ).promise(); + } + }, + entityIdPlainFormatter: { + format: function( entityId ) { + return $.Deferred().resolve( entityId ).promise(); + } + }, valueViewBuilder: 'i am a valueview builder', claimsChanger: 'I am a ClaimsChanger', entityChangersFactory: { diff --git a/lib/tests/qunit/jquery.wikibase/resources.php b/lib/tests/qunit/jquery.wikibase/resources.php index 5492573..a76596b 100644 --- a/lib/tests/qunit/jquery.wikibase/resources.php +++ b/lib/tests/qunit/jquery.wikibase/resources.php @@ -61,6 +61,7 @@ 'wikibase.datamodel.StatementGroup', 'wikibase.datamodel.StatementGroupSet', 'wikibase.datamodel.StatementList', + 'wikibase.store.EntityStore', ), ), @@ -159,6 +160,7 @@ 'dependencies' => array( 'jquery.wikibase.itemview', 'wikibase.datamodel.Item', + 'wikibase.store.EntityStore', ), ), @@ -197,6 +199,7 @@ 'dependencies' => array( 'jquery.wikibase.propertyview', 'wikibase.datamodel.Property', + 'wikibase.store.EntityStore', ), ), @@ -207,9 +210,7 @@ 'dependencies' => array( 'jquery.valueview.ExpertStore', 'jquery.wikibase.referenceview', - 'mediawiki.Title', 'wikibase.datamodel', - 'wikibase.store.FetchedContent', 'wikibase.ValueViewBuilder', 'valueFormatters' ), diff --git a/lib/tests/qunit/jquery.wikibase/snakview/resources.php b/lib/tests/qunit/jquery.wikibase/snakview/resources.php index fd7e6f5..a939151 100644 --- a/lib/tests/qunit/jquery.wikibase/snakview/resources.php +++ b/lib/tests/qunit/jquery.wikibase/snakview/resources.php @@ -24,17 +24,12 @@ 'dependencies' => array( 'dataTypes.DataTypeStore', 'jquery.wikibase.snakview', - 'mediawiki.Title', - 'wikibase.datamodel.Fingerprint', 'wikibase.datamodel.Property', 'wikibase.datamodel.PropertyNoValueSnak', 'wikibase.datamodel.PropertySomeValueSnak', 'wikibase.datamodel.PropertyValueSnak', - 'wikibase.datamodel.Term', - 'wikibase.datamodel.TermMap', 'wikibase.serialization.SnakDeserializer', 'wikibase.serialization.SnakSerializer', - 'wikibase.store.FetchedContent', ), ), diff --git a/lib/tests/qunit/jquery.wikibase/snakview/snakview.tests.js b/lib/tests/qunit/jquery.wikibase/snakview/snakview.tests.js index 02c9d9d..a745679 100644 --- a/lib/tests/qunit/jquery.wikibase/snakview/snakview.tests.js +++ b/lib/tests/qunit/jquery.wikibase/snakview/snakview.tests.js @@ -20,21 +20,6 @@ } } ) ); -var entityStore = { - get: function() { - return $.Deferred().resolve( new wb.store.FetchedContent( { - title: new mw.Title( 'Property:P1' ), - content: new wb.datamodel.Property( - 'P1', - 'string', - new wb.datamodel.Fingerprint( new wb.datamodel.TermMap( [ - new wb.datamodel.Term( 'en', 'P1' ) - ] ) ) - ) - } ) ); - } -}; - var snakSerializer = new wb.serialization.SnakSerializer(), snakDeserializer = new wb.serialization.SnakDeserializer(); @@ -46,7 +31,21 @@ var createSnakview = function( options, $node ) { options = $.extend( { autoStartEditing: false, - entityStore: entityStore, + entityIdHtmlFormatter: { + format: function() { + return $.Deferred().resolve( 'Label' ).promise(); + } + }, + entityIdPlainFormatter: { + format: function( entityId ) { + return $.Deferred().resolve( entityId ).promise(); + } + }, + entityStore: { + get: function( entityId ) { + return $.Deferred().resolve().promise(); + } + }, valueViewBuilder: 'I am a ValueViewBuilder', dataTypeStore: new dt.DataTypeStore() }, options || {} ); diff --git a/view/resources/entityIdFormatter/EntityIdHtmlFormatter.js b/view/resources/entityIdFormatter/EntityIdHtmlFormatter.js new file mode 100644 index 0000000..80afbde --- /dev/null +++ b/view/resources/entityIdFormatter/EntityIdHtmlFormatter.js @@ -0,0 +1,9 @@ +( function( wb ) { + 'use strict'; + + var SELF = wb.view.entityIdFormatter.EntityIdHtmlFormatter = function() { + }; + + SELF.prototype.format = util.abstractMember; + +}( wikibase ) ); diff --git a/view/resources/entityIdFormatter/EntityIdPlainFormatter.js b/view/resources/entityIdFormatter/EntityIdPlainFormatter.js new file mode 100644 index 0000000..9c7640c --- /dev/null +++ b/view/resources/entityIdFormatter/EntityIdPlainFormatter.js @@ -0,0 +1,9 @@ +( function( wb ) { + 'use strict'; + + var SELF = wb.view.entityIdFormatter.EntityIdPlainFormatter = function() { + }; + + SELF.prototype.format = util.abstractMember; + +}( wikibase ) ); diff --git a/view/resources/entityIdFormatter/SimpleEntityIdHtmlFormatter.js b/view/resources/entityIdFormatter/SimpleEntityIdHtmlFormatter.js new file mode 100644 index 0000000..cc04a61 --- /dev/null +++ b/view/resources/entityIdFormatter/SimpleEntityIdHtmlFormatter.js @@ -0,0 +1,39 @@ +( function( $, wb, util ) { + 'use strict'; + + /** + * @param {wikibase.store.EntityStore} entityStore + */ + wb.view.entityIdFormatter.SimpleEntityIdHtmlFormatter = util.inherit( + 'SimpleEntityIdHtmlFormatter', + wb.view.entityIdFormatter.EntityIdHtmlFormatter, + function( entityStore ) { + if( !entityStore || !( entityStore instanceof wb.store.EntityStore ) ) { + throw new Error( 'Required EntityStore instance not passed' ); + } + this._entityStore = entityStore; + }, + { + _entityStore: null, + + format: function( entityId ) { + var deferred = $.Deferred(); + this._entityStore.get( entityId ).done( function( response ) { + var res; + if( response ) { + res = wb.utilities.ui.buildLinkToEntityPage( + response.getContent(), + response.getTitle() + ); + } else { + res = wb.utilities.ui.buildMissingEntityInfo( entityId, entityId[0] === 'P' ? 'property' : 'item' ); + } + deferred.resolve( $( document.createElement( 'span' ) ).html( res ).html() ); + } ).fail( function() { + // FIXME: check fail + } ); + return deferred.promise(); + } + } + ); +}( jQuery, wikibase, util ) ); diff --git a/view/resources/entityIdFormatter/SimpleEntityIdPlainFormatter.js b/view/resources/entityIdFormatter/SimpleEntityIdPlainFormatter.js new file mode 100644 index 0000000..c9fde08 --- /dev/null +++ b/view/resources/entityIdFormatter/SimpleEntityIdPlainFormatter.js @@ -0,0 +1,37 @@ +( function( $, wb, util ) { + 'use strict'; + + /** + * @param {wikibase.store.EntityStore} entityStore + */ + wb.view.entityIdFormatter.SimpleEntityIdPlainFormatter = util.inherit( + 'SimpleEntityIdPlainFormatter', + wb.view.entityIdFormatter.EntityIdPlainFormatter, + function( entityStore ) { + if( !entityStore || !( entityStore instanceof wb.store.EntityStore ) ) { + throw new Error( 'Required EntityStore instance not passed' ); + } + this._entityStore = entityStore; + }, + { + _entityStore: null, + + format: function( entityId ) { + var deferred = $.Deferred(); + this._entityStore.get( entityId ).done( function( response ) { + var res; + if( response ) { + res = wb.utilities.ui.buildPrettyEntityLabelText( response.getContent() ); + } else { + res = entityId; + } + deferred.resolve( res ); + } ).fail( function() { + // FIXME: check fail + } ); + return deferred.promise(); + } + + } + ); +}( jQuery, wikibase, util ) ); diff --git a/view/resources/entityIdFormatter/namespace.js b/view/resources/entityIdFormatter/namespace.js new file mode 100644 index 0000000..1c76693 --- /dev/null +++ b/view/resources/entityIdFormatter/namespace.js @@ -0,0 +1,5 @@ +( function( wb ) { + 'use strict'; + + wb.view.entityIdFormatter = wb.view.entityIdFormatter || {}; +}( wikibase ) ); diff --git a/view/resources/entityIdFormatter/resources.php b/view/resources/entityIdFormatter/resources.php new file mode 100644 index 0000000..c0fb9e3 --- /dev/null +++ b/view/resources/entityIdFormatter/resources.php @@ -0,0 +1,70 @@ +<?php + +/** + * @license GNU GPL v2+ + * @author Adrian Heine < adrian.he...@wikimedia.de > + */ +return call_user_func( function() { + preg_match( '+' . preg_quote( DIRECTORY_SEPARATOR ) . '(?:vendor|extensions)' + . preg_quote( DIRECTORY_SEPARATOR ) . '.*+', __DIR__, $remoteExtPath ); + + $moduleTemplate = array( + 'localBasePath' => __DIR__, + 'remoteExtPath' => '..' . $remoteExtPath[0] + ); + + $modules = array( + 'wikibase.view.entityIdFormatter.__namespace' => $moduleTemplate + array( + 'scripts' => array( + 'namespace.js' + ), + 'dependencies' => array( + 'wikibase.view.__namespace', + ) + ), + 'wikibase.view.entityIdFormatter.EntityIdHtmlFormatter' => $moduleTemplate + array( + 'scripts' => array( + 'EntityIdHtmlFormatter.js' + ), + 'dependencies' => array( + 'util.inherit', + 'wikibase.view.entityIdFormatter.__namespace', + ) + ), + 'wikibase.view.entityIdFormatter.EntityIdPlainFormatter' => $moduleTemplate + array( + 'scripts' => array( + 'EntityIdPlainFormatter.js' + ), + 'dependencies' => array( + 'util.inherit', + 'wikibase.view.entityIdFormatter.__namespace', + ) + ), + 'wikibase.view.entityIdFormatter.SimpleEntityIdHtmlFormatter' => $moduleTemplate + array( + 'scripts' => array( + 'SimpleEntityIdHtmlFormatter.js' + ), + 'dependencies' => array( + 'util.inherit', + 'wikibase.store.EntityStore', + 'wikibase.utilities', + 'wikibase.view.entityIdFormatter.__namespace', + 'wikibase.view.entityIdFormatter.EntityIdHtmlFormatter', + ) + ), + 'wikibase.view.entityIdFormatter.SimpleEntityIdPlainFormatter' => $moduleTemplate + array( + 'scripts' => array( + 'SimpleEntityIdPlainFormatter.js' + ), + 'dependencies' => array( + 'util.inherit', + 'wikibase.store.EntityStore', + 'wikibase.utilities', + 'wikibase.view.entityIdFormatter.__namespace', + 'wikibase.view.entityIdFormatter.EntityIdPlainFormatter', + ) + ), + ); + + return $modules; +} ); diff --git a/view/resources/resources.php b/view/resources/resources.php index edd593d..2281692 100644 --- a/view/resources/resources.php +++ b/view/resources/resources.php @@ -32,5 +32,8 @@ ), ); - return $modules; + return array_merge( + $modules, + include( __DIR__ . '/entityIdFormatter/resources.php' ) + ); } ); diff --git a/view/tests/qunit/entityIdFormatter/SimpleEntityIdHtmlFormatter.tests.js b/view/tests/qunit/entityIdFormatter/SimpleEntityIdHtmlFormatter.tests.js new file mode 100644 index 0000000..12c134f --- /dev/null +++ b/view/tests/qunit/entityIdFormatter/SimpleEntityIdHtmlFormatter.tests.js @@ -0,0 +1,106 @@ +( function( $, sinon, QUnit, wb, mw ) { + 'use strict'; + + var MODULE = wb.view.entityIdFormatter; + + QUnit.module( 'wikibase.view.entityIdFormatter.SimpleEntityIdHtmlFormatter' ); + + function newFormatterGetter( entityStoreType ) { + var entityStore = new wb.store.EntityStore(); + if( entityStoreType === 'empty' ) { + entityStore.get = function() { return $.Deferred().resolve().promise(); }; + } else if( entityStoreType === 'nolabels' ) { + entityStore.get = function( entityId ) { return $.Deferred().resolve( new wb.store.FetchedContent( { + title: $.extend( new mw.Title( 'title' ), { + namespace: 0, + title: entityId, + ext: null, + fragment: null + } ), + content: new wb.datamodel.Item( entityId ) + } ) ); }; + } else if( entityStoreType === 'withlabels' ) { + entityStore.get = function( entityId ) { + var item = new wb.datamodel.Item( entityId ); + item.getFingerprint().setLabel( mw.config.get( 'wgUserLanguage' ), new wb.datamodel.Term( mw.config.get( 'wgUserLanguage' ), 'Label' ) ); + return $.Deferred().resolve( new wb.store.FetchedContent( { + title: $.extend( new mw.Title( 'title' ), { + namespace: 0, + title: entityId, + ext: null, + fragment: null + } ), + content: item + } ) ); + }; + } + return function() { + return new wb.view.entityIdFormatter.SimpleEntityIdHtmlFormatter( entityStore ); + }; + } + + MODULE.testEntityIdHtmlFormatter.all( MODULE.SimpleEntityIdHtmlFormatter, newFormatterGetter( 'empty' ) ); + MODULE.testEntityIdHtmlFormatter.all( MODULE.SimpleEntityIdHtmlFormatter, newFormatterGetter( 'nolabels' ) ); + MODULE.testEntityIdHtmlFormatter.all( MODULE.SimpleEntityIdHtmlFormatter, newFormatterGetter( 'withlabels' ) ); + + QUnit.test( 'constructor throws error if no entity store is passed', function( assert ) { + assert.throws( function() { + return new wb.view.entityIdFormatter.SimpleEntityIdHtmlFormatter(); + } ); + } ); + + QUnit.test( 'constructor throws error if entity store is not instance of EntityStore', function( assert ) { + assert.throws( function() { + return new wb.view.entityIdFormatter.SimpleEntityIdHtmlFormatter( {} ); + } ); + } ); + + QUnit.test( 'format links to entity when it exists', function( assert ) { + var formatter = newFormatterGetter( 'nolabels' )(); + var done = assert.async(); + formatter.format( 'Q1' ).done( function( res ) { + var $res = $( document.createElement( 'span' ) ).html( res ).children(); + assert.ok( $res.is( 'a' ) ); + assert.ok( $res.attr( 'title' ).match( /Q1/ ) ); + assert.ok( $res.attr( 'href' ).match( /Q1/ ) ); + done(); + } ); + } ); + + QUnit.test( 'format uses label when it exists', function( assert ) { + var formatter = newFormatterGetter( 'withlabels' )(); + var done = assert.async(); + formatter.format( 'Q1' ).done( function( res ) { + assert.equal( $( document.createElement( 'span' ) ).html( res ).find( 'a' ).text(), 'Label' ); + done(); + } ); + } ); + + QUnit.test( 'format adds missing label hint', function( assert ) { + var formatter = newFormatterGetter( 'nolabels' )(); + var done = assert.async(); + formatter.format( 'Q1' ).done( function( res ) { + assert.ok( res.match( /class="wb-entity-undefinedinfo"/ ) ); + done(); + } ); + } ); + + QUnit.test( 'format falls back to the entity id when entity does not exist', function( assert ) { + var formatter = newFormatterGetter( 'empty' )(); + var done = assert.async(); + formatter.format( 'Q1' ).done( function( res ) { + assert.ok( $( document.createElement( 'span' ) ).html( res ).text().match( /^Q1/ ) ); + done(); + } ); + } ); + + QUnit.test( 'format adds hint if entity is missing', function( assert ) { + var formatter = newFormatterGetter( 'empty' )(); + var done = assert.async(); + formatter.format( 'Q1' ).done( function( res ) { + assert.ok( res.match( /class="wb-entity-undefinedinfo"/ ) ); + done(); + } ); + } ); + +}( jQuery, sinon, QUnit, wikibase, mediaWiki ) ); diff --git a/view/tests/qunit/entityIdFormatter/SimpleEntityIdPlainFormatter.tests.js b/view/tests/qunit/entityIdFormatter/SimpleEntityIdPlainFormatter.tests.js new file mode 100644 index 0000000..0295802 --- /dev/null +++ b/view/tests/qunit/entityIdFormatter/SimpleEntityIdPlainFormatter.tests.js @@ -0,0 +1,79 @@ +( function( $, sinon, QUnit, wb, mw ) { + 'use strict'; + + QUnit.module( 'wikibase.view.entityIdFormatter.SimpleEntityIdPlainFormatter' ); + + function newFormatterGetter( entityStoreType ) { + var entityStore = new wb.store.EntityStore(); + if( entityStoreType === 'empty' ) { + entityStore.get = function() { return $.Deferred().resolve().promise(); }; + } else if( entityStoreType === 'nolabels' ) { + entityStore.get = function( entityId ) { return $.Deferred().resolve( new wb.store.FetchedContent( { + title: $.extend( new mw.Title( 'title' ), { + namespace: 0, + title: entityId, + ext: null, + fragment: null + } ), + content: new wb.datamodel.Item( entityId ) + } ) ); }; + } else if( entityStoreType === 'withlabels' ) { + entityStore.get = function( entityId ) { + var item = new wb.datamodel.Item( entityId ); + item.getFingerprint().setLabel( mw.config.get( 'wgUserLanguage' ), new wb.datamodel.Term( mw.config.get( 'wgUserLanguage' ), 'Label' ) ); + return $.Deferred().resolve( new wb.store.FetchedContent( { + title: $.extend( new mw.Title( 'title' ), { + namespace: 0, + title: entityId, + ext: null, + fragment: null + } ), + content: item + } ) ); + }; + } + return function() { + return new wb.view.entityIdFormatter.SimpleEntityIdPlainFormatter( entityStore ); + }; + } + + QUnit.test( 'constructor throws error if no entity store is passed', function( assert ) { + assert.throws( function() { + return new wb.view.entityIdFormatter.SimpleEntityIdPlainFormatter(); + } ); + } ); + + QUnit.test( 'constructor throws error if entity store is not instance of EntityStore', function( assert ) { + assert.throws( function() { + return new wb.view.entityIdFormatter.SimpleEntityIdPlainFormatter( {} ); + } ); + } ); + + QUnit.test( 'format uses label when it exists', function( assert ) { + var formatter = newFormatterGetter( 'withlabels' )(); + var done = assert.async(); + formatter.format( 'Q1' ).done( function( res ) { + assert.equal( res, 'Label' ); + done(); + } ); + } ); + + QUnit.test( 'format falls back to the entity id when no label exists', function( assert ) { + var formatter = newFormatterGetter( 'nolabels' )(); + var done = assert.async(); + formatter.format( 'Q1' ).done( function( res ) { + assert.equal( res, 'Q1' ); + done(); + } ); + } ); + + QUnit.test( 'format falls back to the entity id when entity does not exist', function( assert ) { + var formatter = newFormatterGetter( 'empty' )(); + var done = assert.async(); + formatter.format( 'Q1' ).done( function( res ) { + assert.equal( res, 'Q1' ); + done(); + } ); + } ); + +}( jQuery, sinon, QUnit, wikibase, mediaWiki ) ); diff --git a/view/tests/qunit/entityIdFormatter/resources.php b/view/tests/qunit/entityIdFormatter/resources.php new file mode 100644 index 0000000..c3d4122 --- /dev/null +++ b/view/tests/qunit/entityIdFormatter/resources.php @@ -0,0 +1,57 @@ +<?php + +/** + * @license GNU GPL v2+ + * @author Adrian Heine < adrian.he...@wikimedia.de > + */ +return call_user_func( function() { + preg_match( '+' . preg_quote( DIRECTORY_SEPARATOR ) . '(?:vendor|extensions)' + . preg_quote( DIRECTORY_SEPARATOR ) . '.*+', __DIR__, $remoteExtPath ); + + $moduleTemplate = array( + 'localBasePath' => __DIR__, + 'remoteExtPath' => '..' . $remoteExtPath[0] + ); + + $modules = array( + + 'wikibase.view.entityIdFormatter.testEntityIdHtmlFormatter' => $moduleTemplate + array( + 'scripts' => array( + 'testEntityIdHtmlFormatter.js', + ), + 'dependencies' => array( + 'wikibase.view.entityIdFormatter.__namespace', + 'wikibase.view.entityIdFormatter.EntityIdHtmlFormatter', + ), + ), + + 'wikibase.view.entityIdFormatter.SimpleEntityIdHtmlFormatter.tests' => $moduleTemplate + array( + 'scripts' => array( + 'SimpleEntityIdHtmlFormatter.tests.js', + ), + 'dependencies' => array( + 'wikibase.datamodel.Item', + 'wikibase.datamodel.Term', + 'wikibase.store.FetchedContent', + 'wikibase.view.entityIdFormatter.SimpleEntityIdHtmlFormatter', + 'wikibase.view.entityIdFormatter.testEntityIdHtmlFormatter', + ), + ), + + 'wikibase.view.entityIdFormatter.SimpleEntityIdPlainFormatter.tests' => $moduleTemplate + array( + 'scripts' => array( + 'SimpleEntityIdPlainFormatter.tests.js', + ), + 'dependencies' => array( + 'wikibase.datamodel.Item', + 'wikibase.datamodel.Term', + 'wikibase.store.FetchedContent', + 'wikibase.view.entityIdFormatter.SimpleEntityIdPlainFormatter', + ), + ), + + ); + + return $modules; + +} ); diff --git a/view/tests/qunit/entityIdFormatter/testEntityIdHtmlFormatter.js b/view/tests/qunit/entityIdFormatter/testEntityIdHtmlFormatter.js new file mode 100644 index 0000000..4464d1b --- /dev/null +++ b/view/tests/qunit/entityIdFormatter/testEntityIdHtmlFormatter.js @@ -0,0 +1,57 @@ +( function( $, QUnit, wb ) { + 'use strict'; + + wb.view.entityIdFormatter.testEntityIdHtmlFormatter = { + all: function( constructor, getInstance ) { + this.constructorTests( constructor, getInstance ); + this.formatTests( getInstance ); + }, + + constructorTests: function( constructor, getInstance ) { + QUnit.test( 'Constructor', function( assert ) { + var instance = getInstance(); + + assert.ok( + instance instanceof constructor, + 'Instantiated.' + ); + + assert.ok( + instance instanceof wb.view.entityIdFormatter.EntityIdHtmlFormatter, + 'Instance of EntityIdHtmlFormatter' + ); + } ); + }, + + formatTests: function( getInstance ) { + QUnit.test( 'format returns some non-empty string', function( assert ) { + var instance = getInstance(); + var done = assert.async(); + + instance.format( 'Q1' ).done( function( res ) { + assert.equal( typeof res, 'string' ); + assert.notEqual( res, '' ); + done(); + } ); + } ); + QUnit.test( 'format correctly escapes ampersands in the entity id', function( assert ) { + var instance = getInstance(); + var done = assert.async(); + + instance.format( '&' ).done( function( res ) { + assert.equal( res.match( /&($|[^a])/ ), null ); + done(); + } ); + } ); + QUnit.test( 'format correctly escapes HTML in the entity id', function( assert ) { + var instance = getInstance(); + var done = assert.async(); + + instance.format( '<script>' ).done( function( res ) { + assert.equal( $( document.createElement( 'span' ) ).html( res ).find( 'script' ).length, 0 ); + done(); + } ); + } ); + } + }; +}( jQuery, QUnit, wikibase ) ); diff --git a/view/tests/qunit/resources.php b/view/tests/qunit/resources.php index 5e0bc17..4a52209 100644 --- a/view/tests/qunit/resources.php +++ b/view/tests/qunit/resources.php @@ -27,5 +27,9 @@ ); - return $modules; + return array_merge( + $modules, + include( __DIR__ . '/entityIdFormatter/resources.php' ) + ); + } ); -- To view, visit https://gerrit.wikimedia.org/r/199295 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I4a2fdfbc3faa8a640683006111539812ab764faf Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/Wikibase Gerrit-Branch: master Gerrit-Owner: Adrian Lang <adrian.he...@wikimedia.de> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits