jenkins-bot has submitted this change and it was merged. Change subject: New Wikidata Build - 08/10/2014 ......................................................................
New Wikidata Build - 08/10/2014 Change-Id: I23f910d0eea469b1686da80222c92eaa475f06d1 --- M WikibaseClient.settings.php M WikibaseRepo.settings.php M composer.lock M extensions/Wikibase/client/resources/Resources.php M extensions/Wikibase/client/resources/wikibase.client.linkitem.init.js M extensions/Wikibase/lib/includes/ChangesTable.php M extensions/Wikibase/lib/includes/ValuesFinder.php M extensions/Wikibase/lib/includes/serializers/ByPropertyListSerializer.php M extensions/Wikibase/lib/includes/serializers/ReferenceSerializer.php M extensions/Wikibase/lib/resources/experts/EntityIdInput.js M extensions/Wikibase/lib/resources/jquery.wikibase/jquery.wikibase.badgeselector.js M extensions/Wikibase/lib/resources/jquery.wikibase/snakview/snakview.js M extensions/Wikibase/lib/resources/jquery.wikibase/snakview/snakview.variations.Variation.js D extensions/Wikibase/lib/resources/parsers/EntityIdParser.js M extensions/Wikibase/lib/resources/parsers/getStore.js M extensions/Wikibase/lib/resources/parsers/resources.php M extensions/Wikibase/lib/resources/wikibase.store/store.ApiEntityStore.js M extensions/Wikibase/lib/resources/wikibase.store/store.CombiningEntityStore.js M extensions/Wikibase/lib/resources/wikibase.store/store.EntityStore.js M extensions/Wikibase/lib/resources/wikibase.store/store.MwConfigEntityStore.js M extensions/Wikibase/lib/tests/qunit/jquery.wikibase/jquery.wikibase.badgeselector.tests.js M extensions/Wikibase/lib/tests/qunit/jquery.wikibase/jquery.wikibase.sitelinkgroupview.tests.js M extensions/Wikibase/lib/tests/qunit/jquery.wikibase/jquery.wikibase.sitelinklistview.tests.js D extensions/Wikibase/lib/tests/qunit/parsers/EntityIdParser.tests.js M extensions/Wikibase/lib/tests/qunit/resources.php M extensions/Wikibase/lib/tests/qunit/wikibase.store/store.CombiningEntityStore.tests.js M extensions/Wikibase/repo/i18n/ja.json M extensions/Wikibase/repo/i18n/qqq.json M extensions/Wikibase/repo/includes/EntityParserOutputGenerator.php M extensions/Wikibase/repo/includes/UserLanguageLookup.php M extensions/Wikibase/repo/includes/api/ModifyEntity.php M extensions/Wikibase/repo/includes/api/ParseValue.php M extensions/Wikibase/repo/includes/api/SetReference.php M extensions/Wikibase/repo/includes/api/SetSiteLink.php M extensions/Wikibase/repo/tests/phpunit/includes/UserLanguageLookupTest.php A extensions/Wikibase/repo/tests/phpunit/includes/api/ApiConventionsTest.php M extensions/Wikidata.org/resources/themes/default/wikidata-org.badges.css M vendor/autoload.php M vendor/composer/autoload_classmap.php M vendor/composer/autoload_real.php M vendor/composer/installed.json 41 files changed, 489 insertions(+), 378 deletions(-) Approvals: Aude: Looks good to me, approved WikidataJenkins: Verified jenkins-bot: Verified diff --git a/WikibaseClient.settings.php b/WikibaseClient.settings.php index b740552..fc754d7 100644 --- a/WikibaseClient.settings.php +++ b/WikibaseClient.settings.php @@ -1,2 +1,2 @@ <?php -$wgWBClientSettings["sharedCacheKeyPrefix"] = "wikibase:WBL/1412589408"; \ No newline at end of file +$wgWBClientSettings["sharedCacheKeyPrefix"] = "wikibase:WBL/1412757975"; \ No newline at end of file diff --git a/WikibaseRepo.settings.php b/WikibaseRepo.settings.php index 4b14127..971a3e9 100644 --- a/WikibaseRepo.settings.php +++ b/WikibaseRepo.settings.php @@ -1,2 +1,2 @@ <?php -$wgWBRepoSettings["sharedCacheKeyPrefix"] = "wikibase:WBL/1412589408"; \ No newline at end of file +$wgWBRepoSettings["sharedCacheKeyPrefix"] = "wikibase:WBL/1412757975"; \ No newline at end of file diff --git a/composer.lock b/composer.lock index ffe061c..c0140d5 100644 --- a/composer.lock +++ b/composer.lock @@ -835,12 +835,12 @@ "source": { "type": "git", "url": "https://github.com/wmde/Wikidata.org.git", - "reference": "381190e89865e9d0fadcc490ca6f7c7dfdaefb04" + "reference": "217ed7ece8c02fb1474b6ba0cabb936e3ef6c9f1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/wmde/Wikidata.org/zipball/381190e89865e9d0fadcc490ca6f7c7dfdaefb04", - "reference": "381190e89865e9d0fadcc490ca6f7c7dfdaefb04", + "url": "https://api.github.com/repos/wmde/Wikidata.org/zipball/217ed7ece8c02fb1474b6ba0cabb936e3ef6c9f1", + "reference": "217ed7ece8c02fb1474b6ba0cabb936e3ef6c9f1", "shasum": "" }, "require": { @@ -874,7 +874,7 @@ "source": "https://github.com/wmde/Wikidata.org/tree/master", "issues": "https://github.com/wmde/Wikidata.org/issues" }, - "time": "2014-09-26 07:02:41" + "time": "2014-10-06 14:34:12" }, { "name": "wikibase/data-model", @@ -1191,12 +1191,12 @@ "source": { "type": "git", "url": "https://github.com/wikimedia/mediawiki-extensions-Wikibase.git", - "reference": "e9639330cc1c19f60d749f6e587c40e6ad095944" + "reference": "d960d246c53ed44372c7c9bf260bd435004e2365" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/wikimedia/mediawiki-extensions-Wikibase/zipball/e9639330cc1c19f60d749f6e587c40e6ad095944", - "reference": "e9639330cc1c19f60d749f6e587c40e6ad095944", + "url": "https://api.github.com/repos/wikimedia/mediawiki-extensions-Wikibase/zipball/d960d246c53ed44372c7c9bf260bd435004e2365", + "reference": "d960d246c53ed44372c7c9bf260bd435004e2365", "shasum": "" }, "require": { @@ -1265,7 +1265,7 @@ "wikibaserepo", "wikidata" ], - "time": "2014-10-05 20:17:31" + "time": "2014-10-07 17:06:15" }, { "name": "wikibase/wikimedia-badges", diff --git a/extensions/Wikibase/client/resources/Resources.php b/extensions/Wikibase/client/resources/Resources.php index ba5d402..89ac67b 100644 --- a/extensions/Wikibase/client/resources/Resources.php +++ b/extensions/Wikibase/client/resources/Resources.php @@ -8,9 +8,9 @@ ); return array( - 'wikibase.client.getMwRepoForApi' => $moduleTemplate + array( + 'wikibase.client.getMwApiForRepo' => $moduleTemplate + array( 'scripts' => array( - 'wikibase.client.getMwRepoForApi.js' + 'wikibase.client.getMwApiForRepo.js' ), 'dependencies' => array( 'mw.config.values.wbRepo', diff --git a/extensions/Wikibase/client/resources/wikibase.client.linkitem.init.js b/extensions/Wikibase/client/resources/wikibase.client.linkitem.init.js index ad7fce9..a99922f 100644 --- a/extensions/Wikibase/client/resources/wikibase.client.linkitem.init.js +++ b/extensions/Wikibase/client/resources/wikibase.client.linkitem.init.js @@ -21,7 +21,7 @@ 'jquery.wikibase.linkitem', 'mediawiki.Title', 'mw.config.values.wbRepo', - 'wikibase.client.getMwRepoForApi', + 'wikibase.client.getMwApiForRepo', ], function() { $spinner.remove(); diff --git a/extensions/Wikibase/lib/includes/ChangesTable.php b/extensions/Wikibase/lib/includes/ChangesTable.php index 0f63910..f01851d 100644 --- a/extensions/Wikibase/lib/includes/ChangesTable.php +++ b/extensions/Wikibase/lib/includes/ChangesTable.php @@ -29,6 +29,8 @@ } $this->setTargetWiki( $changesDatabase ); + + $this->fieldPrefix = 'change_'; } /** @@ -38,15 +40,6 @@ */ public function getName() { return 'wb_changes'; - } - - /** - * @see ORMTable::getFieldPrefix() - * @since 0.1 - * @return string - */ - protected function getFieldPrefix() { - return 'change_'; } /** diff --git a/extensions/Wikibase/lib/includes/ValuesFinder.php b/extensions/Wikibase/lib/includes/ValuesFinder.php index 720fb6b..e0646d5 100644 --- a/extensions/Wikibase/lib/includes/ValuesFinder.php +++ b/extensions/Wikibase/lib/includes/ValuesFinder.php @@ -2,7 +2,9 @@ namespace Wikibase; +use DataValues\DataValue; use Wikibase\DataModel\Entity\PropertyDataTypeLookup; +use Wikibase\DataModel\Entity\PropertyId; use Wikibase\DataModel\Entity\PropertyNotFoundException; /** @@ -36,7 +38,9 @@ $found = array(); foreach ( $snaks as $snak ) { - if ( $this->isMatchingSnak( $snak, $dataType ) ) { + if ( $snak instanceof PropertyValueSnak && + $this->isMatchingDataType( $snak->getPropertyId(), $dataType ) + ) { $dataValue = $snak->getDataValue(); $found[$dataValue->getHash()] = $dataValue; } @@ -45,22 +49,18 @@ return $found; } - private function isMatchingSnak( Snak $snak, $dataType ) { - if ( !$snak instanceof PropertyValueSnak ) { - return false; - } - + /** + * @param PropertyId $propertyId + * @param string $dataType + * + * @return bool + */ + private function isMatchingDataType( PropertyId $propertyId, $dataType ) { try { - $type = $this->propertyDataTypeLookup->getDataTypeIdForProperty( $snak->getPropertyId() ); + return $this->propertyDataTypeLookup->getDataTypeIdForProperty( $propertyId ) === $dataType; } catch ( PropertyNotFoundException $ex ) { return false; } - - if ( $type !== $dataType ) { - return false; - } - - return true; } } diff --git a/extensions/Wikibase/lib/includes/serializers/ByPropertyListSerializer.php b/extensions/Wikibase/lib/includes/serializers/ByPropertyListSerializer.php index 5af57d2..ef758d4 100644 --- a/extensions/Wikibase/lib/includes/serializers/ByPropertyListSerializer.php +++ b/extensions/Wikibase/lib/includes/serializers/ByPropertyListSerializer.php @@ -68,6 +68,7 @@ $serialization = array(); + $objects = clone $objects; // Don't mangle the original // FIXME: "iterator => array => iterator" is stupid $objects = new ByPropertyIdArray( iterator_to_array( $objects ) ); $objects->buildIndex(); diff --git a/extensions/Wikibase/lib/includes/serializers/ReferenceSerializer.php b/extensions/Wikibase/lib/includes/serializers/ReferenceSerializer.php index 39a9698..316b268 100644 --- a/extensions/Wikibase/lib/includes/serializers/ReferenceSerializer.php +++ b/extensions/Wikibase/lib/includes/serializers/ReferenceSerializer.php @@ -63,11 +63,12 @@ $listSerializer = new ListSerializer( 'snak', $this->snakSerializer, $this->options ); } - $serialization['snaks'] = $listSerializer->getSerialized( $reference->getSnaks() ); + $snaks = $reference->getSnaks(); + $serialization['snaks'] = $listSerializer->getSerialized( $snaks ); $serialization['snaks-order'] = array(); /** @var Snak $snak */ - foreach( $reference->getSnaks() as $snak ) { + foreach( $snaks as $snak ) { $id = $snak->getPropertyId()->getPrefixedId(); if( !in_array( $id, $serialization['snaks-order'] ) ) { $serialization['snaks-order'][] = $id; diff --git a/extensions/Wikibase/lib/resources/experts/EntityIdInput.js b/extensions/Wikibase/lib/resources/experts/EntityIdInput.js index ffe2acb..81a1000 100644 --- a/extensions/Wikibase/lib/resources/experts/EntityIdInput.js +++ b/extensions/Wikibase/lib/resources/experts/EntityIdInput.js @@ -85,16 +85,8 @@ selectedEntity = entitySelector.selectedEntity(); return selectedEntity ? selectedEntity.id : ''; - }, - - /** - * @see jQuery.valueview.Expert.valueCharacteristics - * - * TODO: remove this once the parsing is done via API - */ - valueCharacteristics: function() { - return { prefixmap: WB_ENTITIES_PREFIXMAP }; } + } ); }( mediaWiki, wikibase, jQuery, jQuery.valueview ) ); diff --git a/extensions/Wikibase/lib/resources/jquery.wikibase/jquery.wikibase.badgeselector.js b/extensions/Wikibase/lib/resources/jquery.wikibase/jquery.wikibase.badgeselector.js index 84b7eb7..31db028 100644 --- a/extensions/Wikibase/lib/resources/jquery.wikibase/jquery.wikibase.badgeselector.js +++ b/extensions/Wikibase/lib/resources/jquery.wikibase/jquery.wikibase.badgeselector.js @@ -327,39 +327,23 @@ * No rejected parameters. */ _fetchItems: function( itemIds ) { - var self = this, - deferred = $.Deferred(), - i = 0; + var deferred = $.Deferred(); - /** - * @param {string} itemId - * @param {wikibase.store.EntityStore} entityStore - * @param {jQuery.Deferred} deferred - */ - function fetchItem( itemId, entityStore, deferred ) { - entityStore.get( itemId ) - .done( function( fetchedContent ) { - if( fetchedContent ) { - badges[itemId] = fetchedContent.getContent(); + this.options.entityStore.getMultiple( itemIds ) + .done( function( items ) { + var item; + for( var i = 0; i < items.length; ++i ) { + if( items[i] ) { + item = items[i].getContent(); + badges[item.getId()] = item; } - if( --i === 0 ) { - deferred.resolve(); - } - } ) - .fail( function() { - // TODO: Have entityStore return a proper RepoApiError object. - deferred.reject(); - } ); - } - - $.each( itemIds, function() { - i++; - fetchItem( this, self.options.entityStore, deferred ); - } ); - - if( $.isEmptyObject( itemIds ) ) { + } deferred.resolve(); - } + } ) + .fail( function() { + // TODO: Have entityStore return a proper RepoApiError object. + deferred.reject(); + } ); return deferred.promise(); }, diff --git a/extensions/Wikibase/lib/resources/jquery.wikibase/snakview/snakview.js b/extensions/Wikibase/lib/resources/jquery.wikibase/snakview/snakview.js index 3ebd418..862f710 100644 --- a/extensions/Wikibase/lib/resources/jquery.wikibase/snakview/snakview.js +++ b/extensions/Wikibase/lib/resources/jquery.wikibase/snakview/snakview.js @@ -112,13 +112,6 @@ _variation: null, /** - * Keeps track of values from previously used variations. This allows to display the same value - * when using a previously used variation again during one edit-mode session. - * @type Object - */ - _recentVariationValues: null, - - /** * The property of the Snak currently represented by the view. * @type {String} */ @@ -169,8 +162,6 @@ _create: function() { // apply template to this.element: PARENT.prototype._create.call( this ); - - this._recentVariationValues = {}; this._entityStore = this.option( 'entityStore' ); this._valueViewBuilder = this.option( 'valueViewBuilder' ); @@ -388,9 +379,6 @@ // TODO: should throw an error somewhere when trying to leave edit mode while // this.snak() still returns null. For now setting {} is a simple solution for non- // existent error handling in the snak UI - - // forget about values set in different variations - this._recentVariationValues = {}; this.element.off( 'keydown.' + this.widgetName ); @@ -650,7 +638,7 @@ * * @since 0.4 * - * @param {String|null} snakType + * @param {String|null} [snakType] * @return String|null */ snakType: function( snakType ) { @@ -683,16 +671,12 @@ */ _updateVariation: function() { var variationsFactory = $.wikibase.snakview.variations, - variationType, snakType = this._snakType, VariationConstructor = variationsFactory.getVariation( snakType ); if( this._variation && ( !this._propertyId || this._variation.constructor !== VariationConstructor ) ) { - // remember variation's value for next time variation is used during same edit mode: - variationType = this._variation.variationSnakConstructor.TYPE; - this._recentVariationValues[ variationType ] = this._variation.value(); this.$snakValue.empty(); @@ -709,10 +693,6 @@ this._entityStore, this._valueViewBuilder ); - variationType = this._variation.variationSnakConstructor.TYPE; - - // display value used last for this variation within same edit-mode session: - this._variation.value( this._recentVariationValues[ variationType ] || {} ); } }, diff --git a/extensions/Wikibase/lib/resources/jquery.wikibase/snakview/snakview.variations.Variation.js b/extensions/Wikibase/lib/resources/jquery.wikibase/snakview/snakview.variations.Variation.js index 965d75b..8932990 100644 --- a/extensions/Wikibase/lib/resources/jquery.wikibase/snakview/snakview.variations.Variation.js +++ b/extensions/Wikibase/lib/resources/jquery.wikibase/snakview/snakview.variations.Variation.js @@ -123,8 +123,7 @@ }, /** - * Will set or return the value of the variation's part of the Snak. This will trigger - * draw() as well. + * Will set or return the value of the variation's part of the Snak. * * @since 0.4 * @@ -139,7 +138,6 @@ return this._getValue(); } this._setValue( value ); - this.draw(); }, /** diff --git a/extensions/Wikibase/lib/resources/parsers/EntityIdParser.js b/extensions/Wikibase/lib/resources/parsers/EntityIdParser.js deleted file mode 100644 index 0cf3059..0000000 --- a/extensions/Wikibase/lib/resources/parsers/EntityIdParser.js +++ /dev/null @@ -1,59 +0,0 @@ -/** - * @licence GNU GPL v2+ - * @author H. Snater < mediaw...@snater.com > - */ -( function( wb, vp, $, util ) { - 'use strict'; - - var PARENT = vp.ValueParser, - constructor = function( options ) { - if ( !options.prefixmap ) { - throw new Error( 'EntityIdParser: Prefix map required for initialization.' ); - } - PARENT.call( this, options ); - }; - - /** - * Constructor for an entity id parser. - * - * @constructor - * @extends vp.ValueParser - * @since 0.4 - */ - wb.EntityIdParser = util.inherit( 'WbEntityIdParser', PARENT, constructor, { - - /** - * @see vp.ValueParser.parse - * @since 0.4 - * - * @param {string} rawValue - * @return {$.Promise} - */ - parse: function( rawValue ) { - var deferred = $.Deferred(), - entityType = null, - numericId = null; - - $.each( this._options.prefixmap, function( prefix, type ) { - if ( rawValue.substr( 0, prefix.length ).toLowerCase() === prefix.toLowerCase() ) { - numericId = rawValue.substr( prefix.length ); - if ( ( /^\d+$/ ).test( numericId ) ) { - numericId = parseInt( numericId, 10 ); - entityType = type; - return false; - } - } - } ); - - if ( entityType ) { - deferred.resolve( new wb.datamodel.EntityId( entityType, numericId ) ); - } else { - // TODO: Use a proper Error object to transport detailed information about the failure. - deferred.reject( 'parsererror' ); - } - - return deferred.promise(); - } - } ); - -}( wikibase, valueParsers, jQuery, util ) ); diff --git a/extensions/Wikibase/lib/resources/parsers/getStore.js b/extensions/Wikibase/lib/resources/parsers/getStore.js index 8d34d0f..fa78791 100644 --- a/extensions/Wikibase/lib/resources/parsers/getStore.js +++ b/extensions/Wikibase/lib/resources/parsers/getStore.js @@ -21,11 +21,6 @@ var parserStore = new vp.ValueParserStore( vp.NullParser ); parserStore.registerDataValueParser( - wb.EntityIdParser, - wb.datamodel.EntityId.TYPE - ); - - parserStore.registerDataValueParser( vp.StringParser, dv.StringValue.TYPE ); @@ -36,7 +31,8 @@ 'globecoordinate': dv.GlobeCoordinateValue.TYPE, 'monolingualtext': dv.MonolingualTextValue.TYPE, 'quantity': dv.QuantityValue.TYPE, - 'time': dv.TimeValue.TYPE + 'time': dv.TimeValue.TYPE, + 'wikibase-entityid': wb.datamodel.EntityId.TYPE }; $.each( parserIdToDataValueType, function( parserId, dvType ) { diff --git a/extensions/Wikibase/lib/resources/parsers/resources.php b/extensions/Wikibase/lib/resources/parsers/resources.php index 1c362f2..dc94ac5 100644 --- a/extensions/Wikibase/lib/resources/parsers/resources.php +++ b/extensions/Wikibase/lib/resources/parsers/resources.php @@ -28,18 +28,6 @@ ), ), - 'wikibase.EntityIdParser' => $moduleTemplate + array( - 'scripts' => array( - 'EntityIdParser.js', - ), - 'dependencies' => array( - 'util.inherit', - 'valueParsers.ValueParser', - 'wikibase', - 'wikibase.datamodel', - ), - ), - 'wikibase.parsers.getStore' => $moduleTemplate + array( 'scripts' => array( 'getStore.js', @@ -51,7 +39,6 @@ 'wikibase.api.ParseValueCaller', 'wikibase.parsers.getApiBasedValueParserConstructor', 'wikibase.datamodel', - 'wikibase.EntityIdParser' ), ), diff --git a/extensions/Wikibase/lib/resources/wikibase.store/store.ApiEntityStore.js b/extensions/Wikibase/lib/resources/wikibase.store/store.ApiEntityStore.js index 11d87c3..c54add7 100644 --- a/extensions/Wikibase/lib/resources/wikibase.store/store.ApiEntityStore.js +++ b/extensions/Wikibase/lib/resources/wikibase.store/store.ApiEntityStore.js @@ -50,16 +50,25 @@ _repoApi: null, /** - * @see wikibase.store.Entity.store.get + * @see wikibase.store.EntityStore.getMultipleRaw */ - get: function( entityId ) { - var deferred = $.Deferred(); + getMultipleRaw: function( entityIds ) { + var deferreds = $.map( entityIds, function() { return $.Deferred(); } ); var self = this; + var entityIdsToFetch = []; + var entityIdToIndex = {}; - if( this._entities.hasOwnProperty( entityId ) ) { - deferred.resolve( this._entities[ entityId ] ); - } else { - this._repoApi.getEntities( entityId, null, this._languages ) + $.each( entityIds, function( i, entityId ) { + if( self._entities.hasOwnProperty( entityId ) ) { + deferreds[i].resolve( self._entities[ entityId ] ); + } else { + entityIdsToFetch.push( entityId ); + entityIdToIndex[ entityId ] = i; + } + } ); + + if( entityIdsToFetch.length > 0 ) { + this._repoApi.getEntities( entityIdsToFetch, null, this._languages ) .done( function( result ) { $.each( result.entities, function( id, entityData ) { if( entityData.missing === '' ) { @@ -73,13 +82,21 @@ self._entities[ entity.getContent().getId() ] = entity; } ); - deferred.resolve( self._entities[ entityId ] ); + $.each( entityIdsToFetch, function( i, entityId ) { + deferreds[ entityIdToIndex[ entityId ] ].resolve( self._entities[ entityId ] ); + } ); } ) // FIXME: Evaluate failing promise - .fail( deferred.reject ); + .fail( function() { + $.each( entityIdsToFetch, function( i, entityId ) { + deferreds[ entityIdToIndex[ entityId ] ].reject(); + } ); + } ); } - return deferred.promise(); + return $.map( deferreds, function( deferred ) { + return deferred.promise(); + } ); } } ); }( wikibase, jQuery ) ); diff --git a/extensions/Wikibase/lib/resources/wikibase.store/store.CombiningEntityStore.js b/extensions/Wikibase/lib/resources/wikibase.store/store.CombiningEntityStore.js index 8cb8fa5..ad205eb 100644 --- a/extensions/Wikibase/lib/resources/wikibase.store/store.CombiningEntityStore.js +++ b/extensions/Wikibase/lib/resources/wikibase.store/store.CombiningEntityStore.js @@ -8,27 +8,86 @@ var MODULE = wb.store; /** - * Sequentially tries a handler on an array until a call succeeds. - * - * @param {*[]} arr - * @param {Function} elemHandler A function taking the values from arr one by one and returning - * a jQuery.Promise. - * @return {jQuery.Promise} + * Like jQuery.when, but does not differentiate between fail and success; + * it just waits for all promises to resolve one way or the other and then + * resolves itself. */ - function asyncFirst( arr, elemHandler ) { + function whenFinished( arr ) { var deferred = $.Deferred(); - var idx = 0; + var returnsExpected = arr.length; + $.each( arr, function( i, promise ) { + promise.always( function() { + if( --returnsExpected <= 0 ) { + deferred.resolve(); + } + } ); + } ); + return deferred.promise(); + } + + /** + * An asynchronous reduce which fails when the first handler fails + */ + function asyncReduce( arr, callback, initialValue ) { + var deferred = $.Deferred(); + var index = 0; + var previousValue = initialValue; + function tryNext() { - if( arr.length <= idx ) { - deferred.reject(); + if( arr.length <= index ) { + deferred.resolve( previousValue ); return; } - elemHandler( arr[ idx++ ] ).done( deferred.resolve ).fail( tryNext ); + callback( previousValue, arr[ index++ ] ).fail( deferred.reject ) + .done( function( newState ) { + previousValue = newState; + tryNext(); + } ); } window.setTimeout( tryNext, 0 ); return deferred.promise(); + } + + /** + * Passes all items from arr to the handlers one after the other until it has a resolution + * for every item + */ + function asyncMapFallback( arr, arrHandlers ) { + var deferreds = $.map( arr, function() { return $.Deferred(); } ); + asyncReduce( arrHandlers, function( state, arrHandler ) { + var deferred = $.Deferred(); + if( state.unresolvedArr.length === 0 ) { + return deferred.reject( state ).promise(); + } + + var nextUnresolvedArr = []; + var nextUnresolvedDeferreds = []; + var promises = arrHandler( state.unresolvedArr ); + $.each( promises, function( i, promise ) { + promise.done( state.unresolvedDeferreds[ i ].resolve ) + .fail( function() { + nextUnresolvedArr.push( state.unresolvedArr[ i ] ); + nextUnresolvedDeferreds.push( state.unresolvedDeferreds[ i ] ); + } ); + } ); + whenFinished( promises ).done( function() { + deferred.resolve( { + unresolvedArr: nextUnresolvedArr, + unresolvedDeferreds: nextUnresolvedDeferreds + } ); + } ); + + return deferred.promise(); + }, { + unresolvedArr: arr, + unresolvedDeferreds: deferreds + } ); + + return $.map( deferreds, function( deferred ) { + return deferred.promise(); + } ); } /** @@ -52,12 +111,14 @@ _stores: null, /** - * @see wikibase.store.Entity.store.get + * @see wikibase.store.EntityStore.getMultipleRaw */ - get: function( entityId ) { - return asyncFirst( this._stores, function( getter ) { - return getter.get( entityId ); - } ); + getMultipleRaw: function( entityIds ) { + return asyncMapFallback( entityIds, $.map( this._stores, function( store ) { + return function( entityIds ) { + return store.getMultipleRaw( entityIds ); + }; + } ) ); } } ); }( wikibase, jQuery ) ); diff --git a/extensions/Wikibase/lib/resources/wikibase.store/store.EntityStore.js b/extensions/Wikibase/lib/resources/wikibase.store/store.EntityStore.js index 5706fed..4742980 100644 --- a/extensions/Wikibase/lib/resources/wikibase.store/store.EntityStore.js +++ b/extensions/Wikibase/lib/resources/wikibase.store/store.EntityStore.js @@ -9,7 +9,11 @@ /** * Entity store managing wikibase.datamodel.Entity objects. + * + * Subclasses have to implement at least one of get, getMultiple or getMultipleRaw. + * * @constructor + * @abstract * @since 0.5 */ var SELF = MODULE.EntityStore = function WbEntityStore() {}; @@ -25,7 +29,57 @@ * - {wikibase.store.FetchedContent|undefined|null} * No rejected parameters. */ - get: util.abstractMember + get: function( entityId ) { + var deferred = $.Deferred(); + + this.getMultiple( [ entityId ] ) + .done( function( entities ) { + deferred.resolve( entities[ 0 ] ); + } ) + // FIXME: Evaluate failing promise + .fail( deferred.reject ); + + return deferred.promise(); + }, + + /** + * Returns a promise resolving to an array with elements entity, undefined or null. + * @since 0.5 + * + * @param {string[]} entityIds + * @return {jQuery.Promise} + * Resolved parameters: + * - {wikibase.store.FetchedContent|undefined|null[]} + * No rejected parameters. + */ + getMultiple: function( entityIds ) { + var deferred = $.Deferred(); + + $.when.apply( $, this.getMultipleRaw( entityIds ) ) + .done( function( /*…*/ ) { + deferred.resolve( $.makeArray( arguments ) ); + } ) + // FIXME: Evaluate failing promise + .fail( function() { + deferred.reject(); + } ); + + return deferred.promise(); + }, + + /** + * Returns an array of promises resolving to entity, undefined or null. + * @since 0.5 + * + * @param {string[]} entityIds + * @return {jQuery.Promise[]} + * Resolved parameters: + * - {wikibase.store.FetchedContent|undefined|null} + * No rejected parameters. + */ + getMultipleRaw: function( entityIds ) { + return $.map( entityIds, $.proxy( this.get, this ) ); + } } ); }( wikibase, jQuery ) ); diff --git a/extensions/Wikibase/lib/resources/wikibase.store/store.MwConfigEntityStore.js b/extensions/Wikibase/lib/resources/wikibase.store/store.MwConfigEntityStore.js index c87a87e..9539b1b 100644 --- a/extensions/Wikibase/lib/resources/wikibase.store/store.MwConfigEntityStore.js +++ b/extensions/Wikibase/lib/resources/wikibase.store/store.MwConfigEntityStore.js @@ -43,7 +43,7 @@ if( !this._fetchedEntities.hasOwnProperty( entityId ) ) { deferred.reject(); } else { - if( !( this._fetchedEntities[entityId] instanceof wb.store.FetchedContent ) ) { + if( !( this._fetchedEntities[entityId] instanceof MODULE.FetchedContent ) ) { this._fetchedEntities[entityId] = this._fetchedEntityUnserializer.unserialize( this._fetchedEntities[entityId] ); diff --git a/extensions/Wikibase/lib/tests/qunit/jquery.wikibase/jquery.wikibase.badgeselector.tests.js b/extensions/Wikibase/lib/tests/qunit/jquery.wikibase/jquery.wikibase.badgeselector.tests.js index f462b53..b02a3cc 100644 --- a/extensions/Wikibase/lib/tests/qunit/jquery.wikibase/jquery.wikibase.badgeselector.tests.js +++ b/extensions/Wikibase/lib/tests/qunit/jquery.wikibase/jquery.wikibase.badgeselector.tests.js @@ -18,9 +18,7 @@ } } ) ); -var entityStore = new wb.store.EntityStore( 'i am an abstracted repo api' ); - -entityStore.compile( { +var entities = { Q1: new wb.store.FetchedContent( { title: new mw.Title( 'Item:Q1' ), content: new wb.datamodel.Item( { @@ -45,7 +43,12 @@ labels: { en: { language: 'en', value: 'Q3-label' } } } ) } ) -} ); +}; + +var entityStore = new wb.store.EntityStore(); +entityStore.get = function( entityId ) { + return $.Deferred().resolve( entities[entityId] ); +}; /** * @param {Object} [options] diff --git a/extensions/Wikibase/lib/tests/qunit/jquery.wikibase/jquery.wikibase.sitelinkgroupview.tests.js b/extensions/Wikibase/lib/tests/qunit/jquery.wikibase/jquery.wikibase.sitelinkgroupview.tests.js index 9791133..703bf62 100644 --- a/extensions/Wikibase/lib/tests/qunit/jquery.wikibase/jquery.wikibase.sitelinkgroupview.tests.js +++ b/extensions/Wikibase/lib/tests/qunit/jquery.wikibase/jquery.wikibase.sitelinkgroupview.tests.js @@ -131,22 +131,38 @@ ); } ); - sitelinkgroupview.startEditing(); - sitelinkgroupview.startEditing(); // should not trigger event - sitelinkgroupview.stopEditing( true ); - sitelinkgroupview.stopEditing( true ); // should not trigger event - sitelinkgroupview.stopEditing(); // should not trigger event + function p1() { + $sitelinkgroupview.one( 'sitelinkgroupviewafterstartediting', p2 ); + sitelinkgroupview.startEditing(); + sitelinkgroupview.startEditing(); // should not trigger event + } - sitelinkgroupview.startEditing(); + function p2() { + $sitelinkgroupview.one( 'sitelinkgroupviewafterstopediting', p3 ); + sitelinkgroupview.stopEditing( true ); + sitelinkgroupview.stopEditing( true ); // should not trigger event + sitelinkgroupview.stopEditing(); // should not trigger event + } - // Mock adding a new item: - var sitelinklistview = sitelinkgroupview.$sitelinklistview.data( 'sitelinklistview' ), - listview = sitelinklistview.$listview.data( 'listview' ), - lia = listview.listItemAdapter(), - $sitelinkview = listview.addItem( new wb.datamodel.SiteLink( 'aawiki', 'aawiki-page' ) ); - lia.liInstance( $sitelinkview ).startEditing(); + function p3() { + $sitelinkgroupview.one( 'sitelinkgroupviewafterstartediting', p4 ); + sitelinkgroupview.startEditing(); - sitelinkgroupview.stopEditing(); + // Mock adding a new item: + var sitelinklistview = sitelinkgroupview.$sitelinklistview.data( 'sitelinklistview' ), + listview = sitelinklistview.$listview.data( 'listview' ), + lia = listview.listItemAdapter(), + $sitelinkview = listview.addItem( new wb.datamodel.SiteLink( 'aawiki', 'aawiki-page' ) ); + lia.liInstance( $sitelinkview ).startEditing(); + } + + function p4() { + QUnit.start(); + sitelinkgroupview.stopEditing(); + } + + p1(); + QUnit.stop(); } ); QUnit.test( 'setError()', 1, function( assert ) { diff --git a/extensions/Wikibase/lib/tests/qunit/jquery.wikibase/jquery.wikibase.sitelinklistview.tests.js b/extensions/Wikibase/lib/tests/qunit/jquery.wikibase/jquery.wikibase.sitelinklistview.tests.js index 537a844..a6495ea 100644 --- a/extensions/Wikibase/lib/tests/qunit/jquery.wikibase/jquery.wikibase.sitelinklistview.tests.js +++ b/extensions/Wikibase/lib/tests/qunit/jquery.wikibase/jquery.wikibase.sitelinklistview.tests.js @@ -213,21 +213,41 @@ ); } ); - sitelinklistview.startEditing(); - sitelinklistview.startEditing(); // should not trigger event - sitelinklistview.stopEditing( true ); - sitelinklistview.stopEditing( true ); // should not trigger event - sitelinklistview.stopEditing(); // should not trigger event + function p1() { + $sitelinklistview.one( 'sitelinklistviewafterstartediting', p2 ); + sitelinklistview.startEditing(); + sitelinklistview.startEditing(); // should not trigger event + } - sitelinklistview.startEditing(); + function p2() { + $sitelinklistview.one( 'sitelinklistviewafterstopediting', p3 ); + sitelinklistview.stopEditing( true ); + sitelinklistview.stopEditing( true ); // should not trigger event + sitelinklistview.stopEditing(); // should not trigger event + } - // Mock adding a new item: - var listview = sitelinklistview.$listview.data( 'listview' ), - lia = listview.listItemAdapter(), - $sitelinkview = listview.addItem( new wb.datamodel.SiteLink( 'aawiki', 'aawiki-page' ) ); - lia.liInstance( $sitelinkview ).startEditing(); + function p3() { + $sitelinklistview.one( 'sitelinklistviewafterstartediting', p4 ); + sitelinklistview.startEditing(); - sitelinklistview.stopEditing(); + // Mock adding a new item: + var listview = sitelinklistview.$listview.data( 'listview' ), + lia = listview.listItemAdapter(), + $sitelinkview = listview.addItem( new wb.datamodel.SiteLink( 'aawiki', 'aawiki-page' ) ); + lia.liInstance( $sitelinkview ).startEditing(); + } + + function p4() { + $sitelinklistview.one( 'sitelinklistviewafterstopediting', p5 ); + sitelinklistview.stopEditing( true ); // Have to drop item added above + } + + function p5() { + QUnit.start(); + } + + p1(); + QUnit.stop(); } ); QUnit.test( 'setError()', 1, function( assert ) { diff --git a/extensions/Wikibase/lib/tests/qunit/parsers/EntityIdParser.tests.js b/extensions/Wikibase/lib/tests/qunit/parsers/EntityIdParser.tests.js deleted file mode 100644 index 6b81dc0..0000000 --- a/extensions/Wikibase/lib/tests/qunit/parsers/EntityIdParser.tests.js +++ /dev/null @@ -1,66 +0,0 @@ -/** - * @licence GNU GPL v2+ - * @author Jeroen De Dauw < jeroended...@gmail.com > - */ -( function( wb, vp, util ) { - 'use strict'; - - var PARENT = vp.tests.ValueParserTest; - - /** - * Constructor for creating a test object holding tests for the EntityIdParser. - * - * @constructor - * @extends valueParsers.tests.ValueParserTest - * @since 0.1 - */ - wb.tests.EntityIdParserTest = util.inherit( PARENT, { - - /** - * @see vp.tests.ValueParserTest.getObject - */ - getConstructor: function() { - return wb.EntityIdParser; - }, - - /** - * @see vp.tests.ValueParserTest.getParseArguments - */ - getParseArguments: function() { - // FIXME: right now encapsulation is broken since settings are pulled in server side - // This can be fixed as soon as the parser gets implemented properly - var validValues = { - 'Q1': ['item', 1], - 'P1': ['property', 1], - 'Q42': ['item', 42], - 'P42': ['property', 42] - }; - - var argLists = []; - - // build a list with arrays as entries, [0] is parser input, [1] expected output: - for ( var rawValue in validValues ) { - if ( validValues.hasOwnProperty( rawValue ) ) { - argLists.push( [ rawValue, new wb.datamodel.EntityId( validValues[rawValue][0], validValues[rawValue][1] ) ] ); - } - } - - return argLists; - }, - - getDefaultConstructorArgs: function() { - return [{ - 'prefixmap': { - 'Q': 'item', - 'P': 'property' - } - }]; - } - - } ); - - var test = new wb.tests.EntityIdParserTest(); - - test.runTests( 'wikibase.parsers.EntityIdParser' ); - -}( wikibase, valueParsers, util ) ); diff --git a/extensions/Wikibase/lib/tests/qunit/resources.php b/extensions/Wikibase/lib/tests/qunit/resources.php index a141cc2..aaab898 100644 --- a/extensions/Wikibase/lib/tests/qunit/resources.php +++ b/extensions/Wikibase/lib/tests/qunit/resources.php @@ -53,20 +53,6 @@ ), ), - 'wikibase.parsers.EntityIdParser.tests' => $moduleBase + array( - 'scripts' => array( - 'parsers/EntityIdParser.tests.js', - ), - 'dependencies' => array( - 'util.inherit', - 'valueParsers.tests', - 'wikibase.tests', - 'wikibase.datamodel', - 'wikibase.EntityIdParser', - 'wikibase.tests.qunit.testrunner', - ), - ), - 'wikibase.dataTypes.tests' => $moduleBase + array( 'scripts' => array( 'wikibase.dataTypes/wikibase.dataTypes.tests.js', @@ -109,6 +95,7 @@ ), 'dependencies' => array( 'wikibase.store.CombiningEntityStore', + 'wikibase.store.EntityStore', ), ), diff --git a/extensions/Wikibase/lib/tests/qunit/wikibase.store/store.CombiningEntityStore.tests.js b/extensions/Wikibase/lib/tests/qunit/wikibase.store/store.CombiningEntityStore.tests.js index 2b02416..8cdf1f9 100644 --- a/extensions/Wikibase/lib/tests/qunit/wikibase.store/store.CombiningEntityStore.tests.js +++ b/extensions/Wikibase/lib/tests/qunit/wikibase.store/store.CombiningEntityStore.tests.js @@ -23,11 +23,11 @@ 'Promise is resolved asynchronously, even if the entity is cached', 2, function( assert ) { - var entityStore = new wb.store.CombiningEntityStore( [ { - get: function( entityId ) { - return $.Deferred().resolve(); - } - } ] ); + var store = new wb.store.EntityStore(); + store.get = function( entityId ) { + return $.Deferred().resolve(); + }; + var entityStore = new wb.store.CombiningEntityStore( [ store ] ); var promise = entityStore.get( 'id' ); assert.equal( promise.state(), 'pending', 'Promise is pending.' ); diff --git a/extensions/Wikibase/repo/i18n/ja.json b/extensions/Wikibase/repo/i18n/ja.json index 78f1ec6..b9e2fd3 100644 --- a/extensions/Wikibase/repo/i18n/ja.json +++ b/extensions/Wikibase/repo/i18n/ja.json @@ -31,7 +31,7 @@ "wikibase-claims": "主張", "wikibase-statements": "文", "wikibase-terms": "他の言語", - "wikibase-sitelinks-empty": "この項目にはサイトリンクがまだありません。", + "wikibase-sitelinks-empty": "この項目にリンクしているページはまだありません。", "wikibase-sitelinks-input-help-message": "この項目に関連するページヘのリンクを設定してください。", "wikibase-remove": "除去", "wikibase-move-up": "上に移動", @@ -39,7 +39,7 @@ "wikibase-undo-title": "「$1」の編集の差し戻し", "wikibase-restore-title": "「$1」の古い版の復元", "wikibase-partial-undo": "編集は部分的に取り消せます。", - "wikibase-omitted-undo-ops": "この編集以降に、対応する{{PLURAL:$1|値}}が変更されたため、$1 件の{{PLURAL:$1|変更}}を表示していません。", + "wikibase-omitted-undo-ops": "編集以降に、{{PLURAL:$1|値}}が変更されたため、$1 件の{{PLURAL:$1|変更}}は取り消せません。", "wikibase-empty-undo": "ここには取り消せるものは何もありません。", "wikibase-undo-revision-error": "取り消しに失敗しました", "wikibase-undo-samerev": "編集を差し戻すには、2 つの異なる版を指定してください", @@ -62,11 +62,12 @@ "wikibase-snakview-property-input-placeholder": "プロパティ", "wikibase-snakview-choosesnaktype": "値の型を指定してください。", "wikibase-snakview-variation-datavaluetypemismatch": "プロパティの定義に従っていない値です。", - "wikibase-snakview-variation-datavaluetypemismatch-details": "値のデータ値の型「$1」は、プロパティのデータ型のデータ値の型「$2」と一致しません。", + "wikibase-snakview-variation-datavaluetypemismatch-details": "プロパティの型「$2」と値の型「$1」の間で予期しない競合が発生しました。", "wikibase-snakview-variation-nonewvaluefordeletedproperty": "削除済みのプロパティについて新しい値を定義することはできません。", "wikibase-snakview-variations-somevalue-label": "不明な値", "wikibase-snakview-variations-novalue-label": "値なし", "wikibase-snakview-snaktypeselector-value": "カスタム値", + "wikibase-snakformat-invalid-value": "無効な値です。", "wikibase-snakformat-propertynotfound": "プロパティが見つかりません。", "wikibase-shortcopyrightwarning": "「$1」をクリックすることで、あなたは[[$2|利用規約]]に同意し、自分の投稿内容を$3のもとで公開することに撤回不可能な形で同意することになります。", "wikibase-copyrighttooltip-acknowledge": "今後の編集についてこれらの規約に同意します。次回からこのメッセージを表示しないでください。", @@ -76,7 +77,7 @@ "wikibase-blockeduser-tooltip-message": "利用者名または IP アドレスがブロックされているため、あなたには編集する権限がありません。", "wikibase-move-error": "データ名前空間内のページは移動できず、データ名前空間内にページを移動させることもできません。", "wikibase-validator-label-conflict": "言語コード $2 に関連付けられたラベル「$1」を持つプロパティ ($3) が既にあります。", - "wikibase-validator-label-with-description-conflict": "言語コード $2 に関連付けられたラベル「$1」および説明「$4」を持つ別の項目 ($3) が既にあります。", + "wikibase-validator-label-with-description-conflict": "言語コード $2 に関連付けられたラベル「$1」および同一の説明テキストを持つ項目 ($3) が既にあります。", "wikibase-validator-label-no-entityid": "ラベルは有効なエンティティ ID にしてください。", "wikibase-wikibaserepopage-not-itemid": "「$1」は有効な項目 ID ではありません。", "wikibase-wikibaserepopage-invalid-langcode": "言語コード「$1」は不明です。システムに登録されている言語コード (「en」など) を使用してください。", @@ -89,6 +90,7 @@ "wikibase-itembytitle-submit": "検索", "wikibase-itembytitle-create": "[{{fullurl:Special:NewItem|site=$1&page=$2}} 項目を新規作成]することもできます。", "wikibase-gotolinkedpage-lookup-site": "サイト:", + "wikibase-gotolinkedpage-lookup-item": "項目 ID:", "special-itemdisambiguation": "項目の曖昧さ回避", "wikibase-itemdisambiguation-lookup-fieldset": "言語やラベルで項目を検索", "wikibase-itemdisambiguation-lookup-language": "言語:", @@ -150,6 +152,11 @@ "wikibase-mergeitems-fromid": "統合元の ID", "wikibase-mergeitems-toid": "統合先の ID", "wikibase-mergeitems-submit": "項目を統合", + "wikibase-itemmerge-not-item": "指定したエンティティは項目ではありません。", + "wikibase-itemmerge-failed-save": "項目を保存できませんでした。", + "wikibase-itemmerge-no-such-entity": "項目が見つかりません。", + "wikibase-itemmerge-cant-load-entity-content": "項目を読み込めませんでした。", + "wikibase-tokencheck-missingtoken": "編集トークンが必要です。", "special-dispatchstats": "変更発送統計", "wikibase-dispatchstats-intro": "このページはクライアントに発送された変更についての統計情報を提供します。", "wikibase-dispatchstats-no-stats": "現在利用できる統計はありません。", @@ -190,6 +197,7 @@ "wikibase-entitydata-bad-revision": "エンティティ $1 の版 $2 を表示できません。", "wikibase-entitydata-bad-id": "無効な ID です: $1", "wikibase-entitydata-unsupported-format": "このインターフェイスはデータ形式 $1 に対応していません。", + "wikibase-entitydata-storage-error": "エンティティ $1 を読み込めませんでした。", "wikibase-entitydata-title": "エンティティのデータ", "wikibase-entitydata-text": "このページではエンティティの値にリンクされたデータ インターフェイスを提供します。下位ページの構文を使用して、URL にエンティティ ID を指定してください。", "special-mylanguagefallbackchain": "言語フォールバックチェイン", @@ -270,7 +278,7 @@ "wikibase-property-summary-wbsetaliases-remove": "[$2] の{{PLURAL:$1|別名}}を除去", "wikibase-property-summary-special-create-property": "{{PLURAL:$1|1=値を持つ|0=値を持たない|複数の値を持つ}} [$2] プロパティを作成", "wikibase-listdatatypes-wikibase-item-head": "項目", - "wikibase-listdatatypes-wikibase-item-body": "プロジェクト内の他の項目へのリンク。入力時にウィキデータの項目用名前空間に一致するものがないか検索されます。テキスト入力欄1個で構成されます。", + "wikibase-listdatatypes-wikibase-item-body": "プロジェクト内の他の項目へのリンク。値を入力すると、プロジェクトの「項目」名前空間に一致する項目がないか検索されます。", "wikibase-listdatatypes-commonsmedia-head": "コモンズのメディア", "wikibase-listdatatypes-commonsmedia-body": "ウィキメディア・コモンズで保管されているファイルへのリンク。値の入力時にコモンズのファイル名前空間に一致するファイルがないか検索されます。", "wikibase-listdatatypes-globe-coordinate-head": "座標", diff --git a/extensions/Wikibase/repo/i18n/qqq.json b/extensions/Wikibase/repo/i18n/qqq.json index ae01961..ef56485 100644 --- a/extensions/Wikibase/repo/i18n/qqq.json +++ b/extensions/Wikibase/repo/i18n/qqq.json @@ -259,10 +259,10 @@ "special-entitydata": "{{doc-special|EntityData}}\nThe special page provides a linked data interface and easy way to get the JSON data representation for an entity.", "wikibase-entitydata-not-found": "Error shown when no entity with the given ID could be found (HTTP error 404). Paramters:\n* $1 - the given ID", "wikibase-entitydata-not-acceptable": "Error shown when none of the formats acceptable to the client is suppoerted (HTTP error 406). Paramters:\n* $1 - the list of supported MIME types", - "wikibase-entitydata-bad-revision": "Error shown when the requested revision of a data entity was not found or was not suitable.\n\nParamters:\n* $1 - the entity ID\n* $2 - the requested revision ID", + "wikibase-entitydata-bad-revision": "Error shown when the requested revision of a data entity was not found or was not suitable.\n\nParameters:\n* $1 - the entity ID\n* $2 - the requested revision ID\nSee also:\n* {{msg-mw|Wikibase-entitydata-storage-error}}", "wikibase-entitydata-bad-id": "Error shown when the requested ID is invalid. Parameters:\n* $1: the malformed ID", "wikibase-entitydata-unsupported-format": "Error shown when the requested output format is not supported for entity data (HTTP error 415).\n\nParameters:\n* $1 - the specified data format name", - "wikibase-entitydata-storage-error": "Error shown when the requested entity could not be loaded", + "wikibase-entitydata-storage-error": "Error shown when the requested entity could not be loaded.\n\nParameters:\n* $1 - entity ID\n* $2 - (Unused) revision ID\nSee also:\n* {{msg-mw|Wikibase-entitydata-bad-revision}}", "wikibase-entitydata-title": "Title shown on the special page when a form or text is presented", "wikibase-entitydata-text": "Explanatory text shown on the special page.", "special-mylanguagefallbackchain": "{{doc-special|MyLanguageFallbackChain}}\nThe special page display the language fallback chain used to display Wikibase data for current context.", diff --git a/extensions/Wikibase/repo/includes/EntityParserOutputGenerator.php b/extensions/Wikibase/repo/includes/EntityParserOutputGenerator.php index 610d2a6..c526375 100644 --- a/extensions/Wikibase/repo/includes/EntityParserOutputGenerator.php +++ b/extensions/Wikibase/repo/includes/EntityParserOutputGenerator.php @@ -3,8 +3,8 @@ namespace Wikibase; use ParserOutput; -use Wikibase\DataModel\SiteLinkList; use Wikibase\DataModel\Entity\PropertyDataTypeLookup; +use Wikibase\DataModel\SiteLinkList; use Wikibase\Lib\Serializers\SerializationOptions; use Wikibase\Lib\Store\EntityTitleLookup; @@ -119,14 +119,20 @@ $usedUrls = $valuesFinder->findFromSnaks( $snaks, 'url' ); foreach ( $usedUrls as $url ) { - $pout->addExternalLink( $url->getValue() ); + $value = $url->getValue(); + if ( is_string( $value ) ) { + $pout->addExternalLink( $value ); + } } // treat CommonsMedia values as file transclusions ------ $usedImages = $valuesFinder->findFromSnaks( $snaks, 'commonsMedia' ); - foreach( $usedImages as $image ) { - $pout->addImage( str_replace( ' ', '_', $image->getValue() ) ); + foreach ( $usedImages as $image ) { + $value = $image->getValue(); + if ( is_string( $value ) ) { + $pout->addImage( str_replace( ' ', '_', $value ) ); + } } } diff --git a/extensions/Wikibase/repo/includes/UserLanguageLookup.php b/extensions/Wikibase/repo/includes/UserLanguageLookup.php index c4f9977..259e3d2 100644 --- a/extensions/Wikibase/repo/includes/UserLanguageLookup.php +++ b/extensions/Wikibase/repo/includes/UserLanguageLookup.php @@ -14,6 +14,7 @@ * @licence GNU GPL v2+ * @author Daniel Kinzler * @author Thiemo Mättig + * @author Marius Hoch */ class UserLanguageLookup { @@ -55,8 +56,19 @@ */ public function getUserSpecifiedLanguages( User $user ) { // TODO: If Universal Language Selector (ULS) supports setting additional/alternative - // languages, these should be used in addition or instead of Babel. - return $this->getBabelLanguages( $user ); + // languages, these should be used in addition or instead of Babel (also needs API support). + + $languages = $this->getBabelLanguages( $user ); + + // All languages in MediaWiki are lower-cased, while Babel doesn't enforce + // that for regions. + $languages = array_map( 'strtolower', $languages ); + + $supportedLanguages = Utils::getLanguageCodes(); + $languages = array_intersect( $languages, $supportedLanguages ); + $languages = array_values( $languages ); // Reindex + + return $languages; } /** diff --git a/extensions/Wikibase/repo/includes/api/ModifyEntity.php b/extensions/Wikibase/repo/includes/api/ModifyEntity.php index 15f3bb8..22b7e2d 100644 --- a/extensions/Wikibase/repo/includes/api/ModifyEntity.php +++ b/extensions/Wikibase/repo/includes/api/ModifyEntity.php @@ -519,9 +519,6 @@ autocomment together with the summary is 260 characters. Be aware that everything above that limit will be cut off." ), - 'type' => array( 'A specific type of entity.', - "Will default to 'item' as this will be the most common type." - ), 'token' => 'A "edittoken" token previously obtained through the token module (prop=info).', 'bot' => array( 'Mark this edit as bot', 'This URL flag will only be respected if the user belongs to the group "bot".' diff --git a/extensions/Wikibase/repo/includes/api/ParseValue.php b/extensions/Wikibase/repo/includes/api/ParseValue.php index 1efd1d8..191bf7d 100644 --- a/extensions/Wikibase/repo/includes/api/ParseValue.php +++ b/extensions/Wikibase/repo/includes/api/ParseValue.php @@ -209,7 +209,8 @@ */ protected function getExamples() { return array( - // 'ex' => 'desc' // TODO + 'api.php?action=wbparsevalue&parser=null&values=foo|bar' => 'No change to the format of the string.', + 'api.php?action=wbparsevalue&parser=time&values=1994-02-08&options={"precision":9}' => 'Parse 1994-02-08 to a date format with a precision of 9 (the year).', ); } @@ -224,4 +225,4 @@ return __CLASS__ . '-0.2'; } -} +} \ No newline at end of file diff --git a/extensions/Wikibase/repo/includes/api/SetReference.php b/extensions/Wikibase/repo/includes/api/SetReference.php index e439518..bca0bba 100644 --- a/extensions/Wikibase/repo/includes/api/SetReference.php +++ b/extensions/Wikibase/repo/includes/api/SetReference.php @@ -246,6 +246,7 @@ array( 'statement' => 'A GUID identifying the statement for which a reference is being set', 'snaks' => 'The snaks to set the reference to. JSON object with property ids pointing to arrays containing the snaks for that property', + 'snaks-order' => 'The order of the snaks. Comma-separated list of property ids', 'reference' => 'A hash of the reference that should be updated. Optional. When not provided, a new reference is created', 'index' => 'The index within the statement\'s list of references where to move the reference to. Optional. When not provided, an existing reference will stay in place while a new reference will be appended.', ) diff --git a/extensions/Wikibase/repo/includes/api/SetSiteLink.php b/extensions/Wikibase/repo/includes/api/SetSiteLink.php index 3f0821b..4974b2b 100644 --- a/extensions/Wikibase/repo/includes/api/SetSiteLink.php +++ b/extensions/Wikibase/repo/includes/api/SetSiteLink.php @@ -201,8 +201,8 @@ parent::getParamDescriptionForEntity(), array( 'linksite' => 'The identifier of the site on which the article to link resides', - 'badges' => 'The IDs of items to be set as badges. They will replace the current ones. If this parameter is not set, the badges will not be changed', 'linktitle' => 'The title of the article to link. If this parameter is an empty string or both linktitle and badges are not set, the link will be removed.', + 'badges' => 'The IDs of items to be set as badges. They will replace the current ones. If this parameter is not set, the badges will not be changed', ) ); } diff --git a/extensions/Wikibase/repo/tests/phpunit/includes/UserLanguageLookupTest.php b/extensions/Wikibase/repo/tests/phpunit/includes/UserLanguageLookupTest.php index 0474bf5..a28c827 100644 --- a/extensions/Wikibase/repo/tests/phpunit/includes/UserLanguageLookupTest.php +++ b/extensions/Wikibase/repo/tests/phpunit/includes/UserLanguageLookupTest.php @@ -12,7 +12,6 @@ * @group EntityView * * @licence GNU GPL v2+ - * @author Daniel Kinzler * @author Thiemo Mättig */ class UserLanguageLookupTest extends \PHPUnit_Framework_TestCase { @@ -30,24 +29,31 @@ * TODO: We really want to test grabbing languages from the Babel extension, * but how can we test that? * - * @dataProvider provider + * @dataProvider userLanguagesProvider * * @param string $usersLanguage * @param string $babelLanguages + * @param string $userSpecifiedLanguages * @param string $allExpected * @param string $expectedWithoutDe * @param string $expectedWithoutEn */ - public function testGetUserLanguages( $usersLanguage, $babelLanguages, $allExpected, - $expectedWithoutDe, $expectedWithoutEn ) { - $babelLanguages = $this->split( $babelLanguages ); - $allExpected = $this->split( $allExpected ); - $expectedWithoutDe = $this->split( $expectedWithoutDe ); - $expectedWithoutEn = $this->split( $expectedWithoutEn ); - $hasSpecified = !empty( $babelLanguages ); + public function testGetUserLanguages( + $usersLanguage, + $babelLanguages, + $userSpecifiedLanguages, + $allExpected, + $expectedWithoutDe, + $expectedWithoutEn + ) { + $message = $usersLanguage . ' with {{#babel:' . $babelLanguages . '}} in assert #'; - $message = $usersLanguage . ' width {{#babel:' . implode( '|', $babelLanguages ) . - '}} in assert #'; + $babelLanguages = $this->split( $babelLanguages ); + $userSpecifiedLanguages = $this->split( $userSpecifiedLanguages ); + $allExpected = $this->split( $allExpected ); + $expectedWithoutDe = $this->split( $expectedWithoutDe ); + $expectedWithoutEn = $this->split( $expectedWithoutEn ); + $hasSpecified = !empty( $userSpecifiedLanguages ); $user = new User(); // Required to not be anonymous @@ -66,23 +72,30 @@ $userLanguageLookup->getExtraUserLanguages( $user, array( 'en' ) ) ), $message . '3' ); $this->assertEquals( $hasSpecified, $userLanguageLookup->hasSpecifiedLanguages( $user ), $message . '4' ); - $this->assertEquals( $babelLanguages, + $this->assertEquals( $userSpecifiedLanguages, $userLanguageLookup->getUserSpecifiedLanguages( $user ), $message . '5' ); } - public function provider() { + public function userLanguagesProvider() { return array( // 1. Language from the users settings - // 2. List of languages from the users babel box - // 3. Expected collection of all languages - // 4. Expected extra languages excluding de - // 5. Expected extra languages excluding en - array( 'de', '', 'de', '', 'de' ), - array( 'de', 'en', 'de|en', 'en', 'de' ), - array( 'de', 'de|en|fr', 'de|en|fr', 'en|fr', 'de|fr' ), - array( 'en', '', 'en', 'en', '' ), - array( 'en', 'en', 'en', 'en', '' ), - array( 'en', 'de|en|fr', 'en|de|fr', 'en|fr', 'de|fr' ) + // 2. List of languages from the users babel box (as returned by the Babel extension) + // 3. List of usable user specified languages + // 4. Expected collection of all languages + // 5. Expected extra languages excluding de + // 6. Expected extra languages excluding en + array( 'de', '', '', 'de', '', 'de' ), + array( 'de', 'en', 'en', 'de|en', 'en', 'de' ), + array( 'de', 'de|en|fr', 'de|en|fr', 'de|en|fr', 'en|fr', 'de|fr' ), + array( 'en', '', '', 'en', 'en', '' ), + array( 'en', 'en', 'en', 'en', 'en', '' ), + array( 'en', 'de|en|fr', 'de|en|fr', 'en|de|fr', 'en|fr', 'de|fr' ), + + // Codes reported from Babel are getting lower-cased + array( 'en', 'nds-NL', 'nds-nl', 'en|nds-nl', 'en|nds-nl', 'nds-nl' ), + + // Invalid codes (codes we don't support) returned by Babel get removed + array( 'en', 'invalid-language-code', '', 'en', 'en', '' ), ); } diff --git a/extensions/Wikibase/repo/tests/phpunit/includes/api/ApiConventionsTest.php b/extensions/Wikibase/repo/tests/phpunit/includes/api/ApiConventionsTest.php new file mode 100644 index 0000000..f04dfa7 --- /dev/null +++ b/extensions/Wikibase/repo/tests/phpunit/includes/api/ApiConventionsTest.php @@ -0,0 +1,107 @@ +<?php + +namespace Wikibase\Test\Api; + +use PHPUnit_Framework_TestCase; + +/** + * + * @group Wikibase + * @group WikibaseAPI + * + * @group medium + * + * @licence GNU GPL v2+ + * @author Lucie-Aimée Kaffee + */ +class ApiConventionsTest extends PHPUnit_Framework_TestCase { + + public function wikibaseApiModuleProvider() { + $argList = array(); + + foreach ( $GLOBALS['wgAPIModules'] as $moduleClass ) { + //make sure to only test Wikibase Api modules + if ( strpos( $moduleClass, 'Wikibase' ) !== false ) { + $argList[] = array( $moduleClass ); + } + } + + return $argList; + } + + /** + * Connects the assertions for the different methods and iterates through the api modules + * @dataProvider wikibaseApiModuleProvider + */ + public function testApiConventions( $moduleClass ) { + $params = array(); + $user = $GLOBALS['wgUser']; + + $request = new \FauxRequest( $params, true ); + $main = new \ApiMain( $request ); + $main->getContext()->setUser( $user ); + $module = new $moduleClass( $main, 'moduleClass' ); + + $this->assertGetFinalParamDescription( $moduleClass, $module ); + $this->assertGetExamples( $moduleClass, $module ); + $this->assertGetFinalDescription( $moduleClass, $module ); + } + + /** + * This method is for the assertions in particular for getFinalDescription as defined in ApiBase + * @param string $moduleClass one of the modules in $GLOBALS['wgAPIModules'], only in this function for the error messages + * @param Module $module is an instance of $moduleClass + **/ + private function assertGetFinalDescription ( $moduleClass, $module ) { + $method = 'getFinalDescription'; + $descArray = $module->$method(); + + $rMethod = new \ReflectionMethod( $module, $method ); + $this->assertTrue( $rMethod->isPublic(), 'the method ' . $method . ' of module ' . $moduleClass . ' is not public' ); + + $this->assertNotEmpty( $module->$method(), 'the Module ' . $moduleClass . ' does not have the method ' . $method ); + $this->assertNotEmpty( $descArray, 'the array returned by the method ' . $method . ' of module ' . $moduleClass . ' is empty' ); + foreach ( $descArray as $desc ) { + $this->assertInternalType( 'string', $desc, 'the ' . $desc . '. value returned by the method ' . $method . ' of the module ' . $moduleClass . ' is not a string' ); + } + } + + /** + * This method is for the assertions for getFinalParamDescription as defined in ApiBase, depending on getFinalParams + * @param string $moduleClass one of the modules in $GLOBALS['wgAPIModules'], only in this function for the error messages + * @param Module $module is an instance of $moduleClass + **/ + private function assertGetFinalParamDescription ( $moduleClass, $module ) { + $method = 'getFinalParamDescription'; + $paramsMethod = 'getFinalParams'; + $paramsArray = $module->$paramsMethod(); + if ( !empty( $paramsArray ) ) { + $paramDescArray = $module->$method(); + $this->assertNotEmpty( $paramDescArray, 'the array returned by the method ' . $method . ' of module ' . $moduleClass . ' is empty' ); + + //comparing the keys of the arrays of getParamDescription and getParams + $arrayKeysMatch = !array_diff_key( $paramDescArray, $paramsArray ) && !array_diff_key( $paramsArray, $paramDescArray ); + $this->assertTrue( $arrayKeysMatch, 'keys different at ' . $moduleClass ); + } + } + + /** + * This method is for the assertions of getExamples as defined in ApiBase + * @param string $moduleClass one of the modules in $GLOBALS['wgAPIModules'], only in this function for the error messages + * @param Module $module is an instance of $moduleClass + **/ + private function assertGetExamples( $moduleClass, $module ) { + $method = 'getExamples'; + $rMethod = new \ReflectionMethod( $moduleClass, $method ); + $rMethod->setAccessible( true ); + $exArray = $rMethod->invoke( $module ); + + $this->assertNotEmpty( $exArray, 'there are no examples for ' . $moduleClass ); + + foreach ( $exArray as $key => $value ) { + $this->assertContains('api.php?action=', $key, 'the key ' . $key . ' is not an url at ' . $moduleClass ); + $this->assertInternalType( 'string', $value, 'the value of the example for ' . $key . ' in ' . $moduleClass . ' is not a string' ); + } + + } +} \ No newline at end of file diff --git a/extensions/Wikidata.org/resources/themes/default/wikidata-org.badges.css b/extensions/Wikidata.org/resources/themes/default/wikidata-org.badges.css index c1a845d..8e825a1 100644 --- a/extensions/Wikidata.org/resources/themes/default/wikidata-org.badges.css +++ b/extensions/Wikidata.org/resources/themes/default/wikidata-org.badges.css @@ -11,7 +11,7 @@ * compatibility (browsers able to understand gradient syntax support also SVG). * http://pauginer.tumblr.com/post/36614680636/invisible-gradient-technique */ -.wb-badge-featuredarticle { +.wb-badge.wb-badge-featuredarticle { background-image: url(../../images/wb-badges-gold.png); /* @embed */ background-image: -webkit-linear-gradient(transparent, transparent), url(../../images/wb-badges-gold.svg); @@ -19,7 +19,7 @@ background-image: linear-gradient(transparent, transparent), url(../../images/wb-badges-gold.svg); } -.wb-badge-goodarticle { +.wb-badge.wb-badge-goodarticle { background-image: url(../../images/wb-badges-silver.png); /* @embed */ background-image: -webkit-linear-gradient(transparent, transparent), url(../../images/wb-badges-silver.svg); diff --git a/vendor/autoload.php b/vendor/autoload.php index b9c4c3b..f0997a1 100644 --- a/vendor/autoload.php +++ b/vendor/autoload.php @@ -4,4 +4,4 @@ require_once __DIR__ . '/composer' . '/autoload_real.php'; -return ComposerAutoloaderInit9f1649ffd34285dc59ed8c154c6d6526::getLoader(); +return ComposerAutoloaderInitb133ba8e2b346d53bd85a3342a6a176a::getLoader(); diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index 029b6bd..bcd1c71 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -760,6 +760,7 @@ 'Wikibase\\Test\\ActionTestCase' => $baseDir . '/extensions/Wikibase/repo/tests/phpunit/includes/actions/ActionTestCase.php', 'Wikibase\\Test\\AliasSerializerTest' => $baseDir . '/extensions/Wikibase/lib/tests/phpunit/serializers/AliasSerializerTest.php', 'Wikibase\\Test\\ApiErrorReporterTest' => $baseDir . '/extensions/Wikibase/repo/tests/phpunit/includes/api/ApiErrorReporterTest.php', + 'Wikibase\\Test\\Api\\ApiConventionsTest' => $baseDir . '/extensions/Wikibase/repo/tests/phpunit/includes/api/ApiConventionsTest.php', 'Wikibase\\Test\\Api\\ApiHelperFactoryTest' => $baseDir . '/extensions/Wikibase/repo/tests/phpunit/includes/api/ApiHelperFactoryTest.php', 'Wikibase\\Test\\Api\\ApiModuleTestHelper' => $baseDir . '/extensions/Wikibase/repo/tests/phpunit/includes/api/ApiModuleTestHelper.php', 'Wikibase\\Test\\Api\\ApiXmlFormatTest' => $baseDir . '/extensions/Wikibase/repo/tests/phpunit/includes/api/ApiXmlFormatTest.php', diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php index d1807a7..05a3db9 100644 --- a/vendor/composer/autoload_real.php +++ b/vendor/composer/autoload_real.php @@ -2,7 +2,7 @@ // autoload_real.php @generated by Composer -class ComposerAutoloaderInit9f1649ffd34285dc59ed8c154c6d6526 +class ComposerAutoloaderInitb133ba8e2b346d53bd85a3342a6a176a { private static $loader; @@ -19,9 +19,9 @@ return self::$loader; } - spl_autoload_register(array('ComposerAutoloaderInit9f1649ffd34285dc59ed8c154c6d6526', 'loadClassLoader'), true, true); + spl_autoload_register(array('ComposerAutoloaderInitb133ba8e2b346d53bd85a3342a6a176a', 'loadClassLoader'), true, true); self::$loader = $loader = new \Composer\Autoload\ClassLoader(); - spl_autoload_unregister(array('ComposerAutoloaderInit9f1649ffd34285dc59ed8c154c6d6526', 'loadClassLoader')); + spl_autoload_unregister(array('ComposerAutoloaderInitb133ba8e2b346d53bd85a3342a6a176a', 'loadClassLoader')); $map = require __DIR__ . '/autoload_namespaces.php'; foreach ($map as $namespace => $path) { @@ -42,14 +42,14 @@ $includeFiles = require __DIR__ . '/autoload_files.php'; foreach ($includeFiles as $file) { - composerRequire9f1649ffd34285dc59ed8c154c6d6526($file); + composerRequireb133ba8e2b346d53bd85a3342a6a176a($file); } return $loader; } } -function composerRequire9f1649ffd34285dc59ed8c154c6d6526($file) +function composerRequireb133ba8e2b346d53bd85a3342a6a176a($file) { require $file; } diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index c1b75f4..9e62780 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -1180,12 +1180,12 @@ "source": { "type": "git", "url": "https://github.com/wikimedia/mediawiki-extensions-Wikibase.git", - "reference": "e9639330cc1c19f60d749f6e587c40e6ad095944" + "reference": "d960d246c53ed44372c7c9bf260bd435004e2365" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/wikimedia/mediawiki-extensions-Wikibase/zipball/e9639330cc1c19f60d749f6e587c40e6ad095944", - "reference": "e9639330cc1c19f60d749f6e587c40e6ad095944", + "url": "https://api.github.com/repos/wikimedia/mediawiki-extensions-Wikibase/zipball/d960d246c53ed44372c7c9bf260bd435004e2365", + "reference": "d960d246c53ed44372c7c9bf260bd435004e2365", "shasum": "" }, "require": { @@ -1212,7 +1212,7 @@ "conflict": { "mediawiki/mediawiki": "<1.23" }, - "time": "2014-10-05 20:17:31", + "time": "2014-10-07 17:06:15", "type": "mediawiki-extension", "installation-source": "dist", "autoload": { @@ -1316,18 +1316,18 @@ "source": { "type": "git", "url": "https://github.com/wmde/Wikidata.org.git", - "reference": "381190e89865e9d0fadcc490ca6f7c7dfdaefb04" + "reference": "217ed7ece8c02fb1474b6ba0cabb936e3ef6c9f1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/wmde/Wikidata.org/zipball/381190e89865e9d0fadcc490ca6f7c7dfdaefb04", - "reference": "381190e89865e9d0fadcc490ca6f7c7dfdaefb04", + "url": "https://api.github.com/repos/wmde/Wikidata.org/zipball/217ed7ece8c02fb1474b6ba0cabb936e3ef6c9f1", + "reference": "217ed7ece8c02fb1474b6ba0cabb936e3ef6c9f1", "shasum": "" }, "require": { "php": ">=5.3.0" }, - "time": "2014-09-26 07:02:41", + "time": "2014-10-06 14:34:12", "type": "mediawiki-extension", "installation-source": "dist", "autoload": { -- To view, visit https://gerrit.wikimedia.org/r/165451 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I23f910d0eea469b1686da80222c92eaa475f06d1 Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/Wikidata Gerrit-Branch: master Gerrit-Owner: Aude <aude.w...@gmail.com> Gerrit-Reviewer: Addshore <addshorew...@gmail.com> Gerrit-Reviewer: Aude <aude.w...@gmail.com> Gerrit-Reviewer: Siebrand <siebr...@kitano.nl> Gerrit-Reviewer: Tobias Gritschacher <tobias.gritschac...@wikimedia.de> Gerrit-Reviewer: WikidataJenkins <wikidata-servi...@wikimedia.de> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits