jenkins-bot has submitted this change and it was merged. Change subject: Introduce wikibase.entityIdFormatter ......................................................................
Introduce wikibase.entityIdFormatter This wraps entity fetching and calling the EntityId formatting functions from `wikibase.utilities.ui` in new service classes and passes them to the views. It is a necessary prerequisite for being able to swap out the EntityId formatting logic with a different implementation. It also frees the views from knowing how to format EntityIds and removes the duplicate EntityId formatting code. Change-Id: I4a2fdfbc3faa8a640683006111539812ab764faf --- M .jshintrc M view/resources/jquery/wikibase/jquery.wikibase.referenceview.js M view/resources/jquery/wikibase/jquery.wikibase.snaklistview.js M view/resources/jquery/wikibase/jquery.wikibase.statementgrouplistview.js M view/resources/jquery/wikibase/jquery.wikibase.statementgroupview.js M view/resources/jquery/wikibase/jquery.wikibase.statementlistview.js M view/resources/jquery/wikibase/jquery.wikibase.statementview.js M view/resources/jquery/wikibase/resources.php M view/resources/jquery/wikibase/snakview/resources.php M view/resources/jquery/wikibase/snakview/snakview.js M view/resources/resources.php A view/resources/wikibase/entityIdFormatter/EntityIdHtmlFormatter.js A view/resources/wikibase/entityIdFormatter/EntityIdPlainFormatter.js A view/resources/wikibase/entityIdFormatter/SimpleEntityIdHtmlFormatter.js A view/resources/wikibase/entityIdFormatter/SimpleEntityIdPlainFormatter.js A view/resources/wikibase/entityIdFormatter/namespace.js A view/resources/wikibase/entityIdFormatter/resources.php M view/tests/qunit/jquery/wikibase/jquery.wikibase.itemview.tests.js M view/tests/qunit/jquery/wikibase/jquery.wikibase.propertyview.tests.js M view/tests/qunit/jquery/wikibase/jquery.wikibase.referenceview.tests.js M view/tests/qunit/jquery/wikibase/jquery.wikibase.snaklistview.tests.js M view/tests/qunit/jquery/wikibase/jquery.wikibase.statementgrouplistview.tests.js M view/tests/qunit/jquery/wikibase/jquery.wikibase.statementgroupview.tests.js M view/tests/qunit/jquery/wikibase/jquery.wikibase.statementlistview.tests.js M view/tests/qunit/jquery/wikibase/jquery.wikibase.statementview.tests.js M view/tests/qunit/jquery/wikibase/resources.php M view/tests/qunit/jquery/wikibase/snakview/resources.php M view/tests/qunit/jquery/wikibase/snakview/snakview.tests.js M view/tests/qunit/resources.php A view/tests/qunit/wikibase/entityIdFormatter/SimpleEntityIdHtmlFormatter.tests.js A view/tests/qunit/wikibase/entityIdFormatter/SimpleEntityIdPlainFormatter.tests.js A view/tests/qunit/wikibase/entityIdFormatter/resources.php A view/tests/qunit/wikibase/entityIdFormatter/testEntityIdHtmlFormatter.js 33 files changed, 659 insertions(+), 123 deletions(-) Approvals: Hoo man: Looks good to me, approved jenkins-bot: Verified diff --git a/.jshintrc b/.jshintrc index 988c787..eeade04 100644 --- a/.jshintrc +++ b/.jshintrc @@ -50,6 +50,11 @@ "globals": { "QUnit": false } + }, + "view/tests/qunit/wikibase/entityIdFormatter/testEntityIdHtmlFormatter.js": { + "globals": { + "QUnit": false + } } } diff --git a/view/resources/jquery/wikibase/jquery.wikibase.referenceview.js b/view/resources/jquery/wikibase/jquery.wikibase.referenceview.js index 1a9ee33..07e9246 100644 --- a/view/resources/jquery/wikibase/jquery.wikibase.referenceview.js +++ b/view/resources/jquery/wikibase/jquery.wikibase.referenceview.js @@ -18,6 +18,10 @@ * @param {wikibase.datamodel.Reference|null} options.value * @param {string} options.statementGuid * The GUID of the `Statement` the `Reference` represented by the widget instance belongs to. + * @param {wikibase.entityIdFormatter.EntityIdHtmlFormatter} options.entityIdHtmlFormatter + * Required for dynamically rendering links to `Entity`s. + * @param {wikibase.entityIdFormatter.EntityIdPlainFormatter} options.entityIdPlainFormatter + * Required for dynamically rendering plain text references to `Entity`s. * @param {wikibase.store.EntityStore} options.entityStore * Required for dynamically gathering `Entity`/`Property` information. * @param {wikibase.ValueViewBuilder} options.valueViewBuilder @@ -74,6 +78,8 @@ }, value: null, statementGuid: null, + entityIdHtmlFormatter: null, + entityIdPlainFormatter: null, entityStore: null, valueViewBuilder: null, referencesChanger: null, @@ -113,6 +119,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/view/resources/jquery/wikibase/jquery.wikibase.snaklistview.js b/view/resources/jquery/wikibase/jquery.wikibase.snaklistview.js index 00a0283..a28cb3b 100644 --- a/view/resources/jquery/wikibase/jquery.wikibase.snaklistview.js +++ b/view/resources/jquery/wikibase/jquery.wikibase.snaklistview.js @@ -22,6 +22,10 @@ * @param {boolean} [singleProperty=true] * If `true`, it is assumed that the widget is filled with `Snak`s featuring a single common * property. + * @param {wikibase.entityIdFormatter.EntityIdHtmlFormatter} options.entityIdHtmlFormatter + * Required for dynamically rendering links to `Entity`s. + * @param {wikibase.entityIdFormatter.EntityIdPlainFormatter} options.entityIdPlainFormatter + * Required for dynamically rendering plain text references to `Entity`s. * @param {wikibase.store.EntityStore} options.entityStore * Required for dynamically gathering `Entity`/`Property` information. * @param {wikibase.ValueViewBuilder} options.valueViewBuilder @@ -74,6 +78,8 @@ value: null, singleProperty: false, helpMessage: mw.msg( 'wikibase-claimview-snak-new-tooltip' ), + entityIdHtmlFormatter: null, + entityIdPlainFormatter: null, entityStore: null, valueViewBuilder: null, dataTypeStore: null @@ -160,6 +166,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/view/resources/jquery/wikibase/jquery.wikibase.statementgrouplistview.js b/view/resources/jquery/wikibase/jquery.wikibase.statementgrouplistview.js index 45518c7..797a27e 100644 --- a/view/resources/jquery/wikibase/jquery.wikibase.statementgrouplistview.js +++ b/view/resources/jquery/wikibase/jquery.wikibase.statementgrouplistview.js @@ -115,6 +115,12 @@ $listview = $( '<div/>' ).appendTo( this.element ); } + var entityIdHtmlFormatter = new wb.entityIdFormatter.SimpleEntityIdHtmlFormatter( + this.options.entityStore + ); + var entityIdPlainFormatter = new wb.entityIdFormatter.SimpleEntityIdPlainFormatter( + this.options.entityStore + ); $listview.listview( { listItemAdapter: new $.wikibase.listview.ListItemAdapter( { listItemWidget: $.wikibase.statementgroupview, @@ -123,6 +129,8 @@ value: value, claimGuidGenerator: self.options.claimGuidGenerator, dataTypeStore: self.options.dataTypeStore, + entityIdHtmlFormatter: entityIdHtmlFormatter, + entityIdPlainFormatter: entityIdPlainFormatter, entityStore: self.options.entityStore, valueViewBuilder: self.options.valueViewBuilder, entityChangersFactory: self.options.entityChangersFactory diff --git a/view/resources/jquery/wikibase/jquery.wikibase.statementgroupview.js b/view/resources/jquery/wikibase/jquery.wikibase.statementgroupview.js index 6104bca..9509ca2 100644 --- a/view/resources/jquery/wikibase/jquery.wikibase.statementgroupview.js +++ b/view/resources/jquery/wikibase/jquery.wikibase.statementgroupview.js @@ -24,6 +24,10 @@ * "add" button to add new `Statements`. * @param {wikibase.utilities.ClaimGuidGenerator} options.claimGuidGenerator * Required for dynamically generating GUIDs for new `Statement`s. + * @param {wikibase.entityIdFormatter.EntityIdHtmlFormatter} options.entityIdHtmlFormatter + * Required for dynamically rendering links to `Entity`s. + * @param {wikibase.entityIdFormatter.EntityIdPlainFormatter} options.entityIdPlainFormatter + * Required for dynamically rendering plain text references to `Entity`s. * @param {wikibase.store.EntityStore} options.entityStore * Required for dynamically gathering `Entity`/`Property` information. * @param {wikibase.ValueViewBuilder} options.valueViewBuilder @@ -60,6 +64,8 @@ }, value: null, claimGuidGenerator: null, + entityIdHtmlFormatter: null, + entityIdPlainFormatter: null, entityStore: null, valueViewBuilder: null, entityChangersFactory: null, @@ -80,6 +86,7 @@ _create: function() { if( !this.options.claimGuidGenerator + || !this.options.entityIdHtmlFormatter || !this.options.entityStore || !this.options.valueViewBuilder || !this.options.entityChangersFactory @@ -118,22 +125,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 ); } ); }, @@ -155,6 +148,8 @@ ? this.options.value.getItemContainer() : new wb.datamodel.StatementList(), claimGuidGenerator: this.options.claimGuidGenerator, + entityIdHtmlFormatter: this.options.entityIdHtmlFormatter, + entityIdPlainFormatter: this.options.entityIdPlainFormatter, entityStore: this.options.entityStore, valueViewBuilder: this.options.valueViewBuilder, entityChangersFactory: this.options.entityChangersFactory, diff --git a/view/resources/jquery/wikibase/jquery.wikibase.statementlistview.js b/view/resources/jquery/wikibase/jquery.wikibase.statementlistview.js index f23ceb3..2fd2ebe 100644 --- a/view/resources/jquery/wikibase/jquery.wikibase.statementlistview.js +++ b/view/resources/jquery/wikibase/jquery.wikibase.statementlistview.js @@ -28,6 +28,10 @@ * with edit mode being started. * @param {wikibase.utilities.ClaimGuidGenerator} options.claimGuidGenerator * Required for dynamically generating GUIDs for new `Statement`s. + * @param {wikibase.entityIdFormatter.EntityIdHtmlFormatter} options.entityIdHtmlFormatter + * Required for dynamically rendering links to `Entity`s. + * @param {wikibase.entityIdFormatter.EntityIdPlainFormatter} options.entityIdPlainFormatter + * Required for dynamically rendering plain text references to `Entity`s. * @param {wikibase.store.EntityStore} options.entityStore * Required for dynamically gathering `Entity`/`Property` information. * @param {wikibase.ValueViewBuilder} options.valueViewBuilder @@ -81,6 +85,8 @@ }, value: null, claimGuidGenerator: null, + entityIdHtmlFormatter: null, + entityIdPlainFormatter: null, entityStore: null, valueViewBuilder: null, entityChangersFactory: null, @@ -197,6 +203,8 @@ } }, dataTypeStore: self.options.dataTypeStore, + entityIdHtmlFormatter: self.options.entityIdHtmlFormatter, + entityIdPlainFormatter: self.options.entityIdPlainFormatter, entityStore: self.options.entityStore, valueViewBuilder: self.options.valueViewBuilder, claimsChanger: self._claimsChanger, diff --git a/view/resources/jquery/wikibase/jquery.wikibase.statementview.js b/view/resources/jquery/wikibase/jquery.wikibase.statementview.js index ee574da..4bca237 100644 --- a/view/resources/jquery/wikibase/jquery.wikibase.statementview.js +++ b/view/resources/jquery/wikibase/jquery.wikibase.statementview.js @@ -37,6 +37,10 @@ * Required for dynamically generating GUIDs for new `Statement`s. * @param {wikibase.entityChangers.ClaimsChanger} options.claimsChanger * Required to store the view's `Statement`. + * @param {wikibase.entityIdFormatter.EntityIdHtmlFormatter} options.entityIdHtmlFormatter + * Required for dynamically rendering links to `Entity`s. + * @param {wikibase.entityIdFormatter.EntityIdPlainFormatter} options.entityIdPlainFormatter + * Required for dynamically rendering plain text references to `Entity`s. * @param {wikibase.entityChangers.ReferencesChanger} options.referencesChanger * Required to store the `Reference`s gathered from the `referenceview`s aggregated by the * `statementview`. @@ -102,6 +106,8 @@ claimsChanger: null, referencesChanger: null, dataTypeStore: null, + entityIdHtmlFormatter: null, + entityIdPlainFormatter: null, predefined: { mainSnak: false }, @@ -209,6 +215,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() @@ -253,6 +261,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 }; @@ -314,6 +324,8 @@ ? self.options.value.getClaim().getGuid() : null, dataTypeStore: self.options.dataTypeStore, + entityIdHtmlFormatter: self.options.entityIdHtmlFormatter, + entityIdPlainFormatter: self.options.entityIdPlainFormatter, entityStore: self.options.entityStore, valueViewBuilder: self.options.valueViewBuilder, referencesChanger: self.options.referencesChanger @@ -396,14 +408,8 @@ : this.options.predefined.mainSnak.property; 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/view/resources/jquery/wikibase/resources.php b/view/resources/jquery/wikibase/resources.php index 72180f2..316a31b 100644 --- a/view/resources/jquery/wikibase/resources.php +++ b/view/resources/jquery/wikibase/resources.php @@ -71,6 +71,8 @@ 'jquery.wikibase.listview', 'wikibase.datamodel.Item', 'wikibase.datamodel.StatementGroupSet', + 'wikibase.entityIdFormatter.SimpleEntityIdHtmlFormatter', + 'wikibase.entityIdFormatter.SimpleEntityIdPlainFormatter', ), ), @@ -87,7 +89,7 @@ 'wikibase.datamodel.Property', 'wikibase.datamodel.StatementGroup', 'wikibase.datamodel.StatementList', - 'wikibase.utilities', + 'wikibase.utilities.ClaimGuidGenerator', ), ), @@ -356,7 +358,6 @@ 'mediawiki.jqueryMsg', // for {{plural}} and {{gender}} support in messages 'wikibase.buildErrorOutput', 'wikibase.sites', - 'wikibase.utilities', ), ), diff --git a/view/resources/jquery/wikibase/snakview/resources.php b/view/resources/jquery/wikibase/snakview/resources.php index f6f391b..5328ec0 100644 --- a/view/resources/jquery/wikibase/snakview/resources.php +++ b/view/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/view/resources/jquery/wikibase/snakview/snakview.js b/view/resources/jquery/wikibase/snakview/snakview.js index 4bd21cd..439ac06 100644 --- a/view/resources/jquery/wikibase/snakview/snakview.js +++ b/view/resources/jquery/wikibase/snakview/snakview.js @@ -35,6 +35,10 @@ * @param {boolean} [options.autoStartEditing=true] * Whether the `snakview` should switch to edit mode automatically upon initialization if its * initial value is empty. + * @param {wikibase.entityIdFormatter.EntityIdHtmlFormatter} options.entityIdHtmlFormatter + * Required for dynamically rendering links to `Entity`s. + * @param {wikibase.entityIdFormatter.EntityIdPlainFormatter} options.entityIdPlainFormatter + * Required for dynamically rendering plain text references to `Entity`s. * @param {wikibase.store.EntityStore} options.entityStore * Required for dynamically gathering `Entity`/`Property` information. * @param {wikibase.ValueViewBuilder} options.valueViewBuilder @@ -90,6 +94,8 @@ snaktype: false }, autoStartEditing: true, + entityIdPlainFormatter: null, + entityIdHtmlFormatter: null, entityStore: null, valueViewBuilder: null, dataTypeStore: null, @@ -132,6 +138,14 @@ * @protected */ _create: function() { + if( this.options.locked === true || this.options.locked.property === true ) { + if( !( + this.options.value instanceof wb.datamodel.Snak || ( this.options.value && this.options.value.property ) + ) ) { + mw.log.warn( 'You cannot lock the property without specifying a property' ); + } + } + PARENT.prototype._create.call( this ); this._cachedValues = {}; @@ -728,66 +742,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() : propertyId, - 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|string} [property] `Property` object or the property's - * ID string. 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/view/resources/resources.php b/view/resources/resources.php index 1ead957..0c1132b 100644 --- a/view/resources/resources.php +++ b/view/resources/resources.php @@ -11,6 +11,7 @@ include __DIR__ . '/jquery/wikibase/resources.php', include __DIR__ . '/wikibase/resources.php', include __DIR__ . '/wikibase/entityChangers/resources.php', + include __DIR__ . '/wikibase/entityIdFormatter/resources.php', include __DIR__ . '/wikibase/store/resources.php', include __DIR__ . '/wikibase/utilities/resources.php', include __DIR__ . '/wikibase/view/resources.php' diff --git a/view/resources/wikibase/entityIdFormatter/EntityIdHtmlFormatter.js b/view/resources/wikibase/entityIdFormatter/EntityIdHtmlFormatter.js new file mode 100644 index 0000000..8cb24b2 --- /dev/null +++ b/view/resources/wikibase/entityIdFormatter/EntityIdHtmlFormatter.js @@ -0,0 +1,9 @@ +( function( wb ) { + 'use strict'; + + var SELF = wb.entityIdFormatter.EntityIdHtmlFormatter = function() { + }; + + SELF.prototype.format = util.abstractMember; + +}( wikibase ) ); diff --git a/view/resources/wikibase/entityIdFormatter/EntityIdPlainFormatter.js b/view/resources/wikibase/entityIdFormatter/EntityIdPlainFormatter.js new file mode 100644 index 0000000..c45f1be --- /dev/null +++ b/view/resources/wikibase/entityIdFormatter/EntityIdPlainFormatter.js @@ -0,0 +1,9 @@ +( function( wb ) { + 'use strict'; + + var SELF = wb.entityIdFormatter.EntityIdPlainFormatter = function() { + }; + + SELF.prototype.format = util.abstractMember; + +}( wikibase ) ); diff --git a/view/resources/wikibase/entityIdFormatter/SimpleEntityIdHtmlFormatter.js b/view/resources/wikibase/entityIdFormatter/SimpleEntityIdHtmlFormatter.js new file mode 100644 index 0000000..ae675b8 --- /dev/null +++ b/view/resources/wikibase/entityIdFormatter/SimpleEntityIdHtmlFormatter.js @@ -0,0 +1,39 @@ +( function( $, wb, util ) { + 'use strict'; + + /** + * @param {wikibase.store.EntityStore} entityStore + */ + wb.entityIdFormatter.SimpleEntityIdHtmlFormatter = util.inherit( + 'SimpleEntityIdHtmlFormatter', + wb.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/wikibase/entityIdFormatter/SimpleEntityIdPlainFormatter.js b/view/resources/wikibase/entityIdFormatter/SimpleEntityIdPlainFormatter.js new file mode 100644 index 0000000..86f3bb9 --- /dev/null +++ b/view/resources/wikibase/entityIdFormatter/SimpleEntityIdPlainFormatter.js @@ -0,0 +1,37 @@ +( function( $, wb, util ) { + 'use strict'; + + /** + * @param {wikibase.store.EntityStore} entityStore + */ + wb.entityIdFormatter.SimpleEntityIdPlainFormatter = util.inherit( + 'SimpleEntityIdPlainFormatter', + wb.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/wikibase/entityIdFormatter/namespace.js b/view/resources/wikibase/entityIdFormatter/namespace.js new file mode 100644 index 0000000..96ff9e6 --- /dev/null +++ b/view/resources/wikibase/entityIdFormatter/namespace.js @@ -0,0 +1,5 @@ +( function( wb ) { + 'use strict'; + + wb.entityIdFormatter = wb.entityIdFormatter || {}; +}( wikibase ) ); diff --git a/view/resources/wikibase/entityIdFormatter/resources.php b/view/resources/wikibase/entityIdFormatter/resources.php new file mode 100644 index 0000000..95e1b7e --- /dev/null +++ b/view/resources/wikibase/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.entityIdFormatter.__namespace' => $moduleTemplate + array( + 'scripts' => array( + 'namespace.js' + ), + 'dependencies' => array( + 'wikibase.view.__namespace', + ) + ), + 'wikibase.entityIdFormatter.EntityIdHtmlFormatter' => $moduleTemplate + array( + 'scripts' => array( + 'EntityIdHtmlFormatter.js' + ), + 'dependencies' => array( + 'util.inherit', + 'wikibase.entityIdFormatter.__namespace', + ) + ), + 'wikibase.entityIdFormatter.EntityIdPlainFormatter' => $moduleTemplate + array( + 'scripts' => array( + 'EntityIdPlainFormatter.js' + ), + 'dependencies' => array( + 'util.inherit', + 'wikibase.entityIdFormatter.__namespace', + ) + ), + 'wikibase.entityIdFormatter.SimpleEntityIdHtmlFormatter' => $moduleTemplate + array( + 'scripts' => array( + 'SimpleEntityIdHtmlFormatter.js' + ), + 'dependencies' => array( + 'util.inherit', + 'wikibase.store.EntityStore', + 'wikibase.utilities', + 'wikibase.entityIdFormatter.__namespace', + 'wikibase.entityIdFormatter.EntityIdHtmlFormatter', + ) + ), + 'wikibase.entityIdFormatter.SimpleEntityIdPlainFormatter' => $moduleTemplate + array( + 'scripts' => array( + 'SimpleEntityIdPlainFormatter.js' + ), + 'dependencies' => array( + 'util.inherit', + 'wikibase.store.EntityStore', + 'wikibase.utilities', + 'wikibase.entityIdFormatter.__namespace', + 'wikibase.entityIdFormatter.EntityIdPlainFormatter', + ) + ), + ); + + return $modules; +} ); diff --git a/view/tests/qunit/jquery/wikibase/jquery.wikibase.itemview.tests.js b/view/tests/qunit/jquery/wikibase/jquery.wikibase.itemview.tests.js index 45572cd..ea54e9a 100644 --- a/view/tests/qunit/jquery/wikibase/jquery.wikibase.itemview.tests.js +++ b/view/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/view/tests/qunit/jquery/wikibase/jquery.wikibase.propertyview.tests.js b/view/tests/qunit/jquery/wikibase/jquery.wikibase.propertyview.tests.js index 2ec5edd..03c556e 100644 --- a/view/tests/qunit/jquery/wikibase/jquery.wikibase.propertyview.tests.js +++ b/view/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/view/tests/qunit/jquery/wikibase/jquery.wikibase.referenceview.tests.js b/view/tests/qunit/jquery/wikibase/jquery.wikibase.referenceview.tests.js index a43c47d..98e3922 100644 --- a/view/tests/qunit/jquery/wikibase/jquery.wikibase.referenceview.tests.js +++ b/view/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(), @@ -38,7 +21,17 @@ function createReferenceview( options ) { options = $.extend( { statementGuid: 'testGuid', - 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' @@ -191,4 +184,4 @@ ); } ); -} )( jQuery, mediaWiki, wikibase, jQuery.valueview, valueFormatters, QUnit ); +} )( jQuery, wikibase, jQuery.valueview, valueFormatters, QUnit ); diff --git a/view/tests/qunit/jquery/wikibase/jquery.wikibase.snaklistview.tests.js b/view/tests/qunit/jquery/wikibase/jquery.wikibase.snaklistview.tests.js index 08a50ae..748d5b5 100644 --- a/view/tests/qunit/jquery/wikibase/jquery.wikibase.snaklistview.tests.js +++ b/view/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/view/tests/qunit/jquery/wikibase/jquery.wikibase.statementgrouplistview.tests.js b/view/tests/qunit/jquery/wikibase/jquery.wikibase.statementgrouplistview.tests.js index 33d4999..cd0e87b 100644 --- a/view/tests/qunit/jquery/wikibase/jquery.wikibase.statementgrouplistview.tests.js +++ b/view/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/view/tests/qunit/jquery/wikibase/jquery.wikibase.statementgroupview.tests.js b/view/tests/qunit/jquery/wikibase/jquery.wikibase.statementgroupview.tests.js index edf8227..d8bcbf7 100644 --- a/view/tests/qunit/jquery/wikibase/jquery.wikibase.statementgroupview.tests.js +++ b/view/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/view/tests/qunit/jquery/wikibase/jquery.wikibase.statementlistview.tests.js b/view/tests/qunit/jquery/wikibase/jquery.wikibase.statementlistview.tests.js index be6726c..3d27a96 100644 --- a/view/tests/qunit/jquery/wikibase/jquery.wikibase.statementlistview.tests.js +++ b/view/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/view/tests/qunit/jquery/wikibase/jquery.wikibase.statementview.tests.js b/view/tests/qunit/jquery/wikibase/jquery.wikibase.statementview.tests.js index fdf1b96..31a36a7 100644 --- a/view/tests/qunit/jquery/wikibase/jquery.wikibase.statementview.tests.js +++ b/view/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', referencesChanger: 'I am a ReferencesChanger', diff --git a/view/tests/qunit/jquery/wikibase/resources.php b/view/tests/qunit/jquery/wikibase/resources.php index c4a3b3a..6c3d534 100644 --- a/view/tests/qunit/jquery/wikibase/resources.php +++ b/view/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/view/tests/qunit/jquery/wikibase/snakview/resources.php b/view/tests/qunit/jquery/wikibase/snakview/resources.php index fd7e6f5..a939151 100644 --- a/view/tests/qunit/jquery/wikibase/snakview/resources.php +++ b/view/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/view/tests/qunit/jquery/wikibase/snakview/snakview.tests.js b/view/tests/qunit/jquery/wikibase/snakview/snakview.tests.js index 02c9d9d..a745679 100644 --- a/view/tests/qunit/jquery/wikibase/snakview/snakview.tests.js +++ b/view/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/tests/qunit/resources.php b/view/tests/qunit/resources.php index 269fa54..2bfd599 100644 --- a/view/tests/qunit/resources.php +++ b/view/tests/qunit/resources.php @@ -10,6 +10,7 @@ include __DIR__ . '/jquery/wikibase/resources.php', include __DIR__ . '/wikibase/resources.php', include __DIR__ . '/wikibase/entityChangers/resources.php', + include __DIR__ . '/wikibase/entityIdFormatter/resources.php', include __DIR__ . '/wikibase/store/resources.php', include __DIR__ . '/wikibase/utilities/resources.php', include __DIR__ . '/wikibase/view/resources.php' diff --git a/view/tests/qunit/wikibase/entityIdFormatter/SimpleEntityIdHtmlFormatter.tests.js b/view/tests/qunit/wikibase/entityIdFormatter/SimpleEntityIdHtmlFormatter.tests.js new file mode 100644 index 0000000..26729e7 --- /dev/null +++ b/view/tests/qunit/wikibase/entityIdFormatter/SimpleEntityIdHtmlFormatter.tests.js @@ -0,0 +1,106 @@ +( function( $, sinon, QUnit, wb, mw ) { + 'use strict'; + + var MODULE = wb.entityIdFormatter; + + QUnit.module( 'wikibase.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.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.entityIdFormatter.SimpleEntityIdHtmlFormatter(); + } ); + } ); + + QUnit.test( 'constructor throws error if entity store is not instance of EntityStore', function( assert ) { + assert.throws( function() { + return new wb.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/wikibase/entityIdFormatter/SimpleEntityIdPlainFormatter.tests.js b/view/tests/qunit/wikibase/entityIdFormatter/SimpleEntityIdPlainFormatter.tests.js new file mode 100644 index 0000000..ebf93f3 --- /dev/null +++ b/view/tests/qunit/wikibase/entityIdFormatter/SimpleEntityIdPlainFormatter.tests.js @@ -0,0 +1,79 @@ +( function( $, sinon, QUnit, wb, mw ) { + 'use strict'; + + QUnit.module( 'wikibase.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.entityIdFormatter.SimpleEntityIdPlainFormatter( entityStore ); + }; + } + + QUnit.test( 'constructor throws error if no entity store is passed', function( assert ) { + assert.throws( function() { + return new wb.entityIdFormatter.SimpleEntityIdPlainFormatter(); + } ); + } ); + + QUnit.test( 'constructor throws error if entity store is not instance of EntityStore', function( assert ) { + assert.throws( function() { + return new wb.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/wikibase/entityIdFormatter/resources.php b/view/tests/qunit/wikibase/entityIdFormatter/resources.php new file mode 100644 index 0000000..6065a08 --- /dev/null +++ b/view/tests/qunit/wikibase/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.entityIdFormatter.testEntityIdHtmlFormatter' => $moduleTemplate + array( + 'scripts' => array( + 'testEntityIdHtmlFormatter.js', + ), + 'dependencies' => array( + 'wikibase.entityIdFormatter.__namespace', + 'wikibase.entityIdFormatter.EntityIdHtmlFormatter', + ), + ), + + 'wikibase.entityIdFormatter.SimpleEntityIdHtmlFormatter.tests' => $moduleTemplate + array( + 'scripts' => array( + 'SimpleEntityIdHtmlFormatter.tests.js', + ), + 'dependencies' => array( + 'wikibase.datamodel.Item', + 'wikibase.datamodel.Term', + 'wikibase.store.FetchedContent', + 'wikibase.entityIdFormatter.SimpleEntityIdHtmlFormatter', + 'wikibase.entityIdFormatter.testEntityIdHtmlFormatter', + ), + ), + + 'wikibase.entityIdFormatter.SimpleEntityIdPlainFormatter.tests' => $moduleTemplate + array( + 'scripts' => array( + 'SimpleEntityIdPlainFormatter.tests.js', + ), + 'dependencies' => array( + 'wikibase.datamodel.Item', + 'wikibase.datamodel.Term', + 'wikibase.store.FetchedContent', + 'wikibase.entityIdFormatter.SimpleEntityIdPlainFormatter', + ), + ), + + ); + + return $modules; + +} ); diff --git a/view/tests/qunit/wikibase/entityIdFormatter/testEntityIdHtmlFormatter.js b/view/tests/qunit/wikibase/entityIdFormatter/testEntityIdHtmlFormatter.js new file mode 100644 index 0000000..685a563 --- /dev/null +++ b/view/tests/qunit/wikibase/entityIdFormatter/testEntityIdHtmlFormatter.js @@ -0,0 +1,57 @@ +( function( $, QUnit, wb ) { + 'use strict'; + + wb.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.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 ) ); -- To view, visit https://gerrit.wikimedia.org/r/199295 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I4a2fdfbc3faa8a640683006111539812ab764faf Gerrit-PatchSet: 14 Gerrit-Project: mediawiki/extensions/Wikibase Gerrit-Branch: master Gerrit-Owner: Adrian Lang <adrian.he...@wikimedia.de> Gerrit-Reviewer: Adrian Lang <adrian.he...@wikimedia.de> Gerrit-Reviewer: Aude <aude.w...@gmail.com> Gerrit-Reviewer: Bene <benestar.wikime...@gmail.com> Gerrit-Reviewer: Hoo man <h...@online.de> Gerrit-Reviewer: Jonas Kress (WMDE) <jonas.kr...@wikimedia.de> Gerrit-Reviewer: Thiemo Mättig (WMDE) <thiemo.maet...@wikimedia.de> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits