jenkins-bot has submitted this change and it was merged.

Change subject: Adapt to new JavaScript datamodel and serialization
......................................................................


Adapt to new JavaScript datamodel and serialization

Needs
* https://github.com/wmde/WikibaseDataModelJavascript/pull/16
* https://github.com/wmde/WikibaseSerializationJavaScript/pull/6

Bug: 72757
Change-Id: Iafc2ed96df9f4a36b87ea9217eddc653fd3c4b9c
---
M composer.json
M lib/resources/entityChangers/AliasesChanger.js
M lib/resources/entityChangers/ClaimsChanger.js
M lib/resources/entityChangers/EntityChangersFactory.js
M lib/resources/entityChangers/ReferencesChanger.js
M lib/resources/entityChangers/resources.php
M lib/resources/jquery.wikibase/jquery.wikibase.badgeselector.js
M lib/resources/jquery.wikibase/jquery.wikibase.claimgrouplistview.js
M lib/resources/jquery.wikibase/jquery.wikibase.claimlistview.js
M lib/resources/jquery.wikibase/jquery.wikibase.claimview.js
M lib/resources/jquery.wikibase/jquery.wikibase.entityview.js
M lib/resources/jquery.wikibase/jquery.wikibase.referenceview.js
M lib/resources/jquery.wikibase/jquery.wikibase.snaklistview.js
M lib/resources/jquery.wikibase/jquery.wikibase.statementview.js
M lib/resources/jquery.wikibase/snakview/resources.php
M lib/resources/jquery.wikibase/snakview/snakview.js
M lib/resources/jquery.wikibase/snakview/snakview.variations.Value.js
M lib/resources/wikibase.store/resources.php
M lib/resources/wikibase.store/store.ApiEntityStore.js
M lib/resources/wikibase.store/store.FetchedContentUnserializer.js
M lib/resources/wikibase.store/store.MwConfigEntityStore.js
M lib/resources/wikibase.utilities/wikibase.utilities.ui.js
M lib/tests/qunit/entityChangers/AliasesChanger.tests.js
M lib/tests/qunit/entityChangers/ClaimsChanger.tests.js
M lib/tests/qunit/entityChangers/DescriptionsChanger.tests.js
M lib/tests/qunit/entityChangers/LabelsChanger.tests.js
M lib/tests/qunit/entityChangers/ReferencesChanger.tests.js
M lib/tests/qunit/entityChangers/SiteLinksChanger.tests.js
M lib/tests/qunit/entityChangers/resources.php
M lib/tests/qunit/jquery.wikibase/jquery.wikibase.badgeselector.tests.js
A lib/tests/qunit/jquery.wikibase/jquery.wikibase.claimgrouplistview.tests.js
M lib/tests/qunit/jquery.wikibase/jquery.wikibase.claimview.tests.js
M lib/tests/qunit/jquery.wikibase/jquery.wikibase.entityview.tests.js
M lib/tests/qunit/jquery.wikibase/jquery.wikibase.referenceview.tests.js
M lib/tests/qunit/jquery.wikibase/jquery.wikibase.snaklistview.tests.js
M lib/tests/qunit/jquery.wikibase/resources.php
M lib/tests/qunit/wikibase.store/store.MwConfigEntityStore.tests.js
M repo/resources/Resources.php
M repo/resources/wikibase.EntityInitializer.js
M repo/resources/wikibase.ui.entityViewInit.js
40 files changed, 785 insertions(+), 265 deletions(-)

Approvals:
  Tobias Gritschacher: Verified; Looks good to me, but someone else must approve
  Henning Snater: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/composer.json b/composer.json
index 4d0c0b2..1f70d8d 100644
--- a/composer.json
+++ b/composer.json
@@ -36,10 +36,10 @@
                "data-values/value-view": "~0.8.0",
 
                "wikibase/data-model": "~2.0",
-               "wikibase/data-model-javascript": "~0.3.0",
+               "wikibase/data-model-javascript": "~1.0",
                "wikibase/data-model-serialization": "~1.2",
                "wikibase/internal-serialization": "~1.3",
-               "wikibase/serialization-javascript": "~1.1.1",
+               "wikibase/serialization-javascript": "~2.0",
 
                "diff/diff": "~1.0",
                "wikibase/easyrdf_lite": "~0.8.1"
diff --git a/lib/resources/entityChangers/AliasesChanger.js 
b/lib/resources/entityChangers/AliasesChanger.js
index 8a0466a..ac32909 100644
--- a/lib/resources/entityChangers/AliasesChanger.js
+++ b/lib/resources/entityChangers/AliasesChanger.js
@@ -38,7 +38,7 @@
        _api: null,
 
        /**
-        * @param {Object[]} aliases
+        * @param {string[]} aliases
         * @param {string} language
         * @return {jQuery.Promise}
         *         No resolved parameters.
@@ -47,21 +47,23 @@
         */
        setAliases: function( aliases, language ) {
                var deferred = $.Deferred(),
-                       self = this;
+                       self = this,
+                       initialAliases = this._getInitialAliases( language );
 
                this._api.setAliases(
                        this._entity.getId(),
                        this._revisionStore.getAliasesRevision(),
-                       this._getNewAliases( aliases, language ),
-                       this._getRemovedAliases( aliases, language ),
+                       this._getNewAliases( aliases, initialAliases ),
+                       this._getRemovedAliases( aliases, initialAliases ),
                        language
                )
                .done( function( response ) {
                        self._revisionStore.setAliasesRevision( 
response.entity.lastrevid );
 
-                       // FIXME: Introduce setter, get this right
-                       self._entity._data.aliases = self._entity._data.aliases 
|| {};
-                       self._entity._data.aliases[ language ] = aliases;
+                       self._entity.getFingerprint().setAliases(
+                               language,
+                               new wb.datamodel.MultiTerm( language, aliases )
+                       );
 
                        deferred.resolve();
                } )
@@ -73,13 +75,21 @@
        },
 
        /**
-        * @param {string[]} currentAliases
         * @param {string} language
         * @return {string[]}
         */
-       _getNewAliases: function( currentAliases, language ) {
-               var initialAliases = this._entity.getAliases( language ) || [],
-                       newAliases = [];
+       _getInitialAliases: function( language ) {
+               var aliases = this._entity.getFingerprint().getAliasesFor( 
language );
+               return aliases ? aliases.getTexts() : [];
+       },
+
+       /**
+        * @param {string[]} currentAliases
+        * @param {string[]} initialAliases
+        * @return {string[]}
+        */
+       _getNewAliases: function( currentAliases, initialAliases ) {
+               var newAliases = [];
 
                for( var i = 0; i < currentAliases.length; i++ ) {
                        if( $.inArray( currentAliases[i], initialAliases ) === 
-1 ) {
@@ -92,12 +102,11 @@
 
        /**
         * @param {string[]} currentAliases
-        * @param {string} language
+        * @param {string[]} initialAliases
         * @return {string[]}
         */
-       _getRemovedAliases: function( currentAliases, language ) {
-               var initialAliases = this._entity.getAliases( language ) || [],
-                       removedAliases = [];
+       _getRemovedAliases: function( currentAliases, initialAliases ) {
+               var removedAliases = [];
 
                for( var i = 0; i < initialAliases.length; i++ ) {
                        if( $.inArray( initialAliases[i], currentAliases ) === 
-1 ) {
diff --git a/lib/resources/entityChangers/ClaimsChanger.js 
b/lib/resources/entityChangers/ClaimsChanger.js
index 66c7139..fd5ec30 100644
--- a/lib/resources/entityChangers/ClaimsChanger.js
+++ b/lib/resources/entityChangers/ClaimsChanger.js
@@ -14,11 +14,19 @@
  * @param {wikibase.RepoApi} api
  * @param {wikibase.RevisionStore} revisionStore
  * @param {wikibase.datamodel.Entity} entity
+ * @param {wikibase.serialization.ClaimSerializer} claimSerializer
+ * @param {wikibase.serialization.ClaimDeserializer} claimDeserializer
+ * @param {wikibase.serialization.StatementSerializer} statementSerializer
+ * @param {wikibase.serialization.StatementDeserializer} statementDeserializer
  */
-var SELF = MODULE.ClaimsChanger = function( api, revisionStore, entity ) {
+var SELF = MODULE.ClaimsChanger = function( api, revisionStore, entity, 
claimSerializer, claimDeserializer, statementSerializer, statementDeserializer 
) {
        this._api = api;
        this._revisionStore = revisionStore;
        this._entity = entity;
+       this._claimSerializer = claimSerializer;
+       this._claimDeserializer = claimDeserializer;
+       this._statementSerializer = statementSerializer;
+       this._statementDeserializer = statementDeserializer;
 };
 
 $.extend( SELF.prototype, {
@@ -38,22 +46,42 @@
        _api: null,
 
        /**
-        * @param {wikibase.datamodel.Claim} claim
+        * @type {wikibase.serialization.ClaimSerializer}
+        */
+       _claimSerializer: null,
+
+       /**
+        * @type {wikibase.serialization.ClaimDeserializer}
+        */
+       _claimDeserializer: null,
+
+       /**
+        * @type {wikibase.serialization.StatementSerializer}
+        */
+       _statementSerializer: null,
+
+       /**
+        * @type {wikibase.serialization.StatementDeserializer}
+        */
+       _statementDeserializer: null,
+
+       /**
+        * @param {wikibase.datamodel.Statement} statement
         * @return {jQuery.Promise}
         *         No resolved parameters.
         *         Rejected parameters:
         *         - {wikibase.RepoApiError}
         */
-       removeClaim: function( claim ) {
+       removeStatement: function( statement ) {
                var deferred = $.Deferred(),
                        self = this,
-                       guid = claim.getGuid();
+                       guid = statement.getClaim().getGuid();
 
                this._api.removeClaim( guid, 
this._revisionStore.getClaimRevision( guid ) )
                .done( function( response ) {
                        self._revisionStore.setClaimRevision( 
response.pageinfo.lastrevid, guid );
 
-                       // FIXME: Introduce Item.setClaims
+                       // FIXME: Set statement on this._entity
                        deferred.resolve();
                } )
                .fail( function( errorCode, error ) {
@@ -77,18 +105,18 @@
                        deferred = $.Deferred();
 
                this._api.setClaim(
-                       claim.toJSON(),
+                       this._claimSerializer.serialize( claim ),
                        this._revisionStore.getClaimRevision( claim.getGuid() ),
                        index
                )
                .done( function( result ) {
-                       var savedClaim = wb.datamodel.Claim.newFromJSON( 
result.claim ),
+                       var savedClaim = self._claimDeserializer.deserialize( 
result.claim ),
                                pageInfo = result.pageinfo;
 
                        // Update revision store:
                        self._revisionStore.setClaimRevision( 
pageInfo.lastrevid, savedClaim.getGuid() );
 
-                       // FIXME: Introduce Item.setClaims
+                       // FIXME: Set claim on this._entity
 
                        deferred.resolve( savedClaim );
                } )
@@ -97,6 +125,44 @@
                } );
 
                return deferred.promise();
+       },
+
+       /**
+        * @param {wikibase.datamodel.Statement} statement
+        * @param {number} index
+        * @return {Object} jQuery.Promise
+        *         Resolved parameters:
+        *         - {wikibase.datamodel.Statement} The saved statement
+        *         Rejected parameters:
+        *         - {wikibase.RepoApiError}
+        */
+       setStatement: function( statement, index ) {
+               var self = this,
+                       deferred = $.Deferred();
+
+               this._api.setClaim(
+                       this._statementSerializer.serialize( statement ),
+                       this._revisionStore.getClaimRevision( 
statement.getClaim().getGuid() ),
+                       index
+               )
+               .done( function( result ) {
+                       var savedStatement = 
self._statementDeserializer.deserialize( result.claim ),
+                               pageInfo = result.pageinfo;
+
+                       // Update revision store:
+                       self._revisionStore.setClaimRevision(
+                               pageInfo.lastrevid, 
savedStatement.getClaim().getGuid()
+                       );
+
+                       // FIXME: Set statement on this._entity
+
+                       deferred.resolve( savedStatement );
+               } )
+               .fail( function( errorCode, error ) {
+                       deferred.reject( wb.RepoApiError.newFromApiResponse( 
error, 'save' ) );
+               } );
+
+               return deferred.promise();
        }
 } );
 
diff --git a/lib/resources/entityChangers/EntityChangersFactory.js 
b/lib/resources/entityChangers/EntityChangersFactory.js
index 08f0f9f..955e5a7 100644
--- a/lib/resources/entityChangers/EntityChangersFactory.js
+++ b/lib/resources/entityChangers/EntityChangersFactory.js
@@ -48,7 +48,15 @@
         * @return {wikibase.entityChangers.ClaimsChanger}
         */
        getClaimsChanger: function() {
-               return new MODULE.ClaimsChanger( this._api, 
this._revisionStore, this._entity );
+               return new MODULE.ClaimsChanger(
+                       this._api,
+                       this._revisionStore,
+                       this._entity,
+                       new wb.serialization.ClaimSerializer(),
+                       new wb.serialization.ClaimDeserializer(),
+                       new wb.serialization.StatementSerializer(),
+                       new wb.serialization.StatementDeserializer()
+               );
        },
 
        /**
@@ -69,7 +77,13 @@
         * @return {wikibase.entityChangers.ReferencesChanger}
         */
        getReferencesChanger: function() {
-               return new MODULE.ReferencesChanger( this._api, 
this._revisionStore, this._entity );
+               return new MODULE.ReferencesChanger(
+                       this._api,
+                       this._revisionStore,
+                       this._entity,
+                       new wb.serialization.ReferenceSerializer(),
+                       new wb.serialization.ReferenceDeserializer()
+               );
        },
 
        /**
diff --git a/lib/resources/entityChangers/ReferencesChanger.js 
b/lib/resources/entityChangers/ReferencesChanger.js
index 087b45b..3242bbe 100644
--- a/lib/resources/entityChangers/ReferencesChanger.js
+++ b/lib/resources/entityChangers/ReferencesChanger.js
@@ -14,11 +14,21 @@
  * @param {wikibase.RepoApi} api
  * @param {wikibase.RevisionStore} revisionStore
  * @param {wikibase.datamodel.Entity} entity
+ * @param {wikibase.serialization.ReferenceSerializer} referenceSerializer
+ * @param {wikibase.serialization.ReferenceDeserializer} referenceDeserializer
  */
-var SELF = MODULE.ReferencesChanger = function( api, revisionStore, entity ) {
+var SELF = MODULE.ReferencesChanger = function(
+       api,
+       revisionStore,
+       entity,
+       referenceSerializer,
+       referenceDeserializer
+) {
        this._api = api;
        this._revisionStore = revisionStore;
        this._entity = entity;
+       this._referenceSerializer = referenceSerializer;
+       this._referenceDeserializer = referenceDeserializer;
 };
 
 $.extend( SELF.prototype, {
@@ -36,6 +46,16 @@
         * @type {wikibase.RepoApi}
         */
        _api: null,
+
+       /**
+        * @type {wikibase.serialization.ReferenceSerializer}
+        */
+       _referenceSerializer: null,
+
+       /**
+        * @type {wikibase.serialization.ReferenceDeserializer}
+        */
+       _referenceDeserializer: null,
 
        /**
         * @param {string} statementGuid
@@ -57,7 +77,7 @@
                .done( function( result ) {
                        self._revisionStore.setClaimRevision( result.pageinfo, 
statementGuid );
 
-                       // FIXME: Introduce Item.setReferences
+                       // FIXME: Update self._entity
                        deferred.resolve();
                } )
                .fail( function( errorCode, error ) {
@@ -83,19 +103,19 @@
 
                this._api.setReference(
                        statementGuid,
-                       reference.getSnaks().toJSON(),
+                       this._referenceSerializer.serialize( reference ).snaks,
                        this._revisionStore.getClaimRevision( statementGuid ),
                        reference.getHash(),
                        index
                )
                .done( function( result ) {
-                       var savedReference = 
wb.datamodel.Reference.newFromJSON( result.reference ),
+                       var savedReference = 
self._referenceDeserializer.deserialize( result.reference ),
                                pageInfo = result.pageinfo;
 
                        // Update revision store:
                        self._revisionStore.setClaimRevision( 
pageInfo.lastrevid, statementGuid );
 
-                       // FIXME: Introduce Item.setReferences
+                       // FIXME: Update self._entity
 
                        deferred.resolve( savedReference );
                } )
diff --git a/lib/resources/entityChangers/resources.php 
b/lib/resources/entityChangers/resources.php
index 6b0c1ed..74196ae 100644
--- a/lib/resources/entityChangers/resources.php
+++ b/lib/resources/entityChangers/resources.php
@@ -32,6 +32,7 @@
                                'AliasesChanger.js',
                        ),
                        'dependencies' => array(
+                               'wikibase.datamodel.MultiTerm',
                                'wikibase.entityChangers.__namespace',
                                'wikibase.RepoApiError',
                        ),
@@ -69,6 +70,12 @@
                                'wikibase.entityChangers.LabelsChanger',
                                'wikibase.entityChangers.ReferencesChanger',
                                'wikibase.entityChangers.SiteLinksChanger',
+                               'wikibase.serialization.ClaimDeserializer',
+                               'wikibase.serialization.ClaimSerializer',
+                               'wikibase.serialization.ReferenceDeserializer',
+                               'wikibase.serialization.ReferenceSerializer',
+                               'wikibase.serialization.StatementDeserializer',
+                               'wikibase.serialization.StatementSerializer',
                        )
                ),
 
diff --git a/lib/resources/jquery.wikibase/jquery.wikibase.badgeselector.js 
b/lib/resources/jquery.wikibase/jquery.wikibase.badgeselector.js
index 8d77e7f..d282541 100644
--- a/lib/resources/jquery.wikibase/jquery.wikibase.badgeselector.js
+++ b/lib/resources/jquery.wikibase/jquery.wikibase.badgeselector.js
@@ -285,14 +285,17 @@
                        $menu.empty();
 
                        $.each( self.options.badges, function( itemId, 
cssClasses ) {
-                               var item = badges[itemId];
+                               var item = badges[itemId],
+                                       term = item && 
item.getFingerprint().getLabelFor( self.options.languageCode ),
+                                       label = term && term.getText();
+
                                var $item = $( '<a/>' )
                                        .on( 'click.' + self.widgetName, 
function( event ) {
                                                event.preventDefault();
                                        } );
 
                                if( item ) {
-                                       $item.text( item.getLabel( 
self.options.languageCode ) || item.getId() );
+                                       $item.text( label || itemId );
                                } else {
                                        $item.append(
                                                
wb.utilities.ui.buildMissingEntityInfo( itemId, wb.datamodel.Item.TYPE )
@@ -305,7 +308,7 @@
                                .append( $item
                                        .prepend( mw.wbTemplate( 'wb-badge',
                                                itemId + ' ' + cssClasses,
-                                               ( item && item.getLabel( 
self.options.languageCode ) ) || itemId,
+                                               label || itemId,
                                                itemId
                                        ) )
                                )
@@ -396,11 +399,15 @@
         */
        _addBadge: function( badgeId ) {
                var badgeItem = badges[badgeId],
+                       badgeLabelTerm = badgeItem && 
badgeItem.getFingerprint().getLabelFor(
+                               this.options.languageCode
+                       ),
+                       badgeLabel = badgeLabelTerm && badgeLabelTerm.getText(),
                        $placeholderBadge = this.element.children( 
'[data-wb-badge="' + badgeId + '"]' );
 
                var $badge = mw.wbTemplate( 'wb-badge',
                        badgeId + ' ' + this.options.badges[badgeId],
-                       badgeItem && badgeItem.getLabel( 
this.options.languageCode ) || badgeId,
+                       badgeLabel || badgeId,
                        badgeId
                );
 
diff --git 
a/lib/resources/jquery.wikibase/jquery.wikibase.claimgrouplistview.js 
b/lib/resources/jquery.wikibase/jquery.wikibase.claimgrouplistview.js
index b9f3b72..7696c06 100644
--- a/lib/resources/jquery.wikibase/jquery.wikibase.claimgrouplistview.js
+++ b/lib/resources/jquery.wikibase/jquery.wikibase.claimgrouplistview.js
@@ -12,8 +12,9 @@
  * @since 0.5
  * @extends jQuery.TemplatedWidget
  *
- * @option {wb.datamodel.Claim[]|null} value The claims to be displayed by 
this view. If null, the view
- *         will display only an add button to add new claims.
+ * @option 
{wikibase.datamodel.ClaimGroupSet|{wikibase.datamodel.StatementGroupSet} [value]
+ *         The claims to be displayed by this view. If null, the view will 
display only an add
+ *         button to add new claims.
  *         Default: null
  *
  * @option {string} entityType Type of the entity that the claimgrouplistview 
referes to.
@@ -105,7 +106,7 @@
                } );
 
                if( claims ) {
-                       this._initClaims( claims  );
+                       this._initClaims( claims );
                }
        },
 
@@ -114,30 +115,14 @@
         * property.
         * @since 0.5
         *
-        * @param {wb.datamodel.Claim[]} claims
-        *
-        * @todo This method should not be necessary because this.option( 
'value' ) should already
-        * contain proper order information to directly feed the listview.
+        * @param 
{wikibase.datamodel.ClaimGroupSet|wikibase.datamodel.StatementGroupSet} 
claimGroups
         */
-       _initClaims: function( claims ) {
-               var propertyOrder = [],
-                       claimsByProperty = {},
-                       i;
+       _initClaims: function( claimGroups ) {
+               var self = this;
 
-               for( i = 0; i < claims.length; i++ ) {
-                       var propertyId = 
claims[i].getMainSnak().getPropertyId();
-
-                       if( $.inArray( propertyId, propertyOrder ) === -1 ) {
-                               propertyOrder.push( propertyId );
-                               claimsByProperty[propertyId] = [];
-                       }
-
-                       claimsByProperty[propertyId].push( claims[i] );
-               }
-
-               for( i = 0; i < propertyOrder.length; i++ ) {
-                       this.listview().addItem( 
claimsByProperty[propertyOrder[i]] );
-               }
+               claimGroups.each( function( propertyId, claimGroup ) {
+                       self.listview().addItem( claimGroup );
+               } );
        },
 
        /**
@@ -155,16 +140,23 @@
        _createClaimGroupListview: function() {
                var self = this;
 
-               function indexOf( claimsSubset, claims ) {
-                       if(
-                               !$.isArray( claimsSubset ) || 
!claimsSubset.length
-                               || !$.isArray( claims ) || !claims.length
-                       ) {
-                               return null;
-                       }
+               function indexOf( claim, claimGroupSet ) {
+                       var offset = 0,
+                               curIndex = null;
 
-                       var index = $.inArray( claimsSubset[0], claims );
-                       return ( index !== -1 ) ? index : null;
+                       if( !claim || !claimGroupSet ) {
+                               return curIndex;
+                       }
+                       claimGroupSet.each( function( propertyId, claimGroup ) {
+                               var indexInGroup = 
claimGroup.getItemContainer().indexOf( claim );
+                               if( indexInGroup !== -1 ) {
+                                       curIndex = offset + indexInGroup;
+                               } else {
+                                       offset += 
claimGroup.getItemContainer().length;
+                               }
+                               return curIndex === null;
+                       } );
+                       return curIndex;
                }
 
                this.$listview.listview( {
@@ -174,7 +166,10 @@
                                        return {
                                                value: value,
                                                entityType: self.option( 
'entityType' ),
-                                               firstClaimIndex: indexOf( 
value, self.option( 'value' ) ),
+                                               firstClaimIndex: value && 
indexOf(
+                                                       
value.getItemContainer().toArray()[0],
+                                                       self.option( 'value' )
+                                               ),
                                                entityStore: self.option( 
'entityStore' ),
                                                valueViewBuilder: self.option( 
'valueViewBuilder' ),
                                                entityChangersFactory: 
self.option( 'entityChangersFactory' )
@@ -267,17 +262,20 @@
                                // claimlistview featuring the specific 
property yet. Instead, use the already
                                // existing pending claimlistview.
                                // TODO: Assume that there are more than one 
item to be added.
-                               var newClaims = lia.liInstance( $claimlistview 
).value(),
-                                       newPropertyId = 
newClaims[0].getMainSnak().getPropertyId();
+                               var newStatements = lia.liInstance( 
$claimlistview ).value(),
+                                       newPropertyId = 
newStatements[0].getClaim().getMainSnak().getPropertyId();
 
                                self.listview().removeItem( $claimlistview );
 
                                var correspondingClaimlistview = 
self._findClaimlistview( newPropertyId );
 
                                if( correspondingClaimlistview ) {
-                                       
correspondingClaimlistview.listview().addItem( newClaims[0] );
+                                       
correspondingClaimlistview.listview().addItem( newStatements[0] );
                                } else {
-                                       self.listview().addItem( newClaims );
+                                       self.listview().addItem( new 
wb.datamodel.StatementGroup(
+                                               newPropertyId,
+                                               new wb.datamodel.StatementList( 
newStatements )
+                                       ) );
                                }
 
                        } );
@@ -303,7 +301,16 @@
                for( var i = 0; i < $claimlistviews.length; i++ ) {
                        var claimlistview = lia.liInstance( $claimlistviews.eq( 
i ) ),
                                claims = claimlistview.value();
-                       if( claims.length && 
claims[0].getMainSnak().getPropertyId() === propertyId ) {
+
+                       if( !claims.length ) {
+                               continue;
+                       }
+
+                       var mainSnak = claims[0].getMainSnak
+                               ? claims[0].getMainSnak()
+                               : claims[0].getClaim().getMainSnak();
+
+                       if( mainSnak.getPropertyId() === propertyId ) {
                                return claimlistview;
                        }
                }
diff --git a/lib/resources/jquery.wikibase/jquery.wikibase.claimlistview.js 
b/lib/resources/jquery.wikibase/jquery.wikibase.claimlistview.js
index 66534c5..dd5b7e3 100644
--- a/lib/resources/jquery.wikibase/jquery.wikibase.claimlistview.js
+++ b/lib/resources/jquery.wikibase/jquery.wikibase.claimlistview.js
@@ -12,8 +12,9 @@
  * @since 0.4
  * @extends jQuery.TemplatedWidget
  *
- * @option {wb.datamodel.Statement[]|null} value The list of statements to be 
displayed this view. If null, the
- *         view will initialize an empty statementview with edit mode started.
+ * @option {wikibase.datamodel.ClaimGroup|wikibase.datamodel.StatementGroup} 
[value]
+ *         The list of statements to be displayed by this view. If null, the 
view will initialize an
+ *         empty claimview with edit mode started.
  *         Default: null
  *
  * @option {wb.store.EntityStore} entityStore
@@ -54,7 +55,7 @@
                        '', // group name and toolbar
                        function() {
                                var statements = this.option( 'value' );
-                               return statements ? 
statements[0].getMainSnak().getPropertyId() : '';
+                               return statements ? statements.getKey() : '';
                        }
                ],
                templateShortCuts: {
@@ -164,7 +165,7 @@
                        return;
                }
 
-               propertyId = statements[0].getMainSnak().getPropertyId();
+               propertyId = statements.getKey();
 
                this.option( 'entityStore' ).get( propertyId ).done( function( 
property ) {
                        var $title;
@@ -203,7 +204,8 @@
                        propertyId;
 
                if( statements ) {
-                       propertyId = 
statements[0].getMainSnak().getPropertyId();
+                       propertyId = statements.getKey();
+                       statements = statements.getItemContainer().toArray();
                }
 
                function indexOf( element, array, firstClaimIndex ) {
@@ -357,7 +359,7 @@
 
                statementview.disable();
 
-               this._claimsChanger.removeClaim( statementview.value() )
+               this._claimsChanger.removeStatement( statementview.value() )
                .done( function() {
                        self.listview().removeItem( statementview.element );
 
diff --git a/lib/resources/jquery.wikibase/jquery.wikibase.claimview.js 
b/lib/resources/jquery.wikibase/jquery.wikibase.claimview.js
index 2d9e614..95f2188 100644
--- a/lib/resources/jquery.wikibase/jquery.wikibase.claimview.js
+++ b/lib/resources/jquery.wikibase/jquery.wikibase.claimview.js
@@ -369,7 +369,7 @@
                        if( snaklistviews.length ) {
                                for( var i = 0; i < snaklistviews.length; i++ ) 
{
                                        if( snaklistviews[i].value() ) {
-                                               qualifiers.add( 
snaklistviews[i].value() );
+                                               qualifiers.merge( 
snaklistviews[i].value() );
                                        }
                                }
                        }
@@ -522,7 +522,7 @@
                                        } else if ( !dropValue ) {
                                                // Gather all the current snaks 
in a single SnakList to set to reset the
                                                // initial qualifiers:
-                                               this._initialQualifiers.add( 
snaklistviews[i].value() );
+                                               this._initialQualifiers.merge( 
snaklistviews[i].value() );
                                        }
                                }
                        }
@@ -574,7 +574,7 @@
 
                // Combine qualifiers grouped by property to a single SnakList:
                for( var i = 0; i < snaklistviews.length; i++ ) {
-                       qualifiers.add( snaklistviews[i].value() );
+                       qualifiers.merge( snaklistviews[i].value() );
                }
 
                return new wb.datamodel.Claim(
diff --git a/lib/resources/jquery.wikibase/jquery.wikibase.entityview.js 
b/lib/resources/jquery.wikibase/jquery.wikibase.entityview.js
index ed89bbd..c4a1707 100644
--- a/lib/resources/jquery.wikibase/jquery.wikibase.entityview.js
+++ b/lib/resources/jquery.wikibase/jquery.wikibase.entityview.js
@@ -125,13 +125,16 @@
                        ).appendTo( this.element );
                }
 
+               var label = this.options.value.getFingerprint().getLabelFor(
+                       mw.config.get( 'wgUserLanguage' )
+               );
                this.$label.labelview( {
                        value: {
                                language: mw.config.get( 'wgUserLanguage' ),
                                label: this.$label.hasClass( 'wb-empty' )
                                        ? null
                                        // FIXME: entity object should not 
contain fallback strings
-                                       : this.options.value.getLabel( 
mw.config.get( 'wgUserLanguage' ) )
+                                       : ( label && label.getText() )
                        },
                        helpMessage: mw.msg(
                                'wikibase-description-input-help-message',
@@ -149,13 +152,16 @@
                        this.$description = $( '<div/>' ).appendTo( 
this.element );
                }
 
+               var description = 
this.options.value.getFingerprint().getDescriptionFor(
+                       mw.config.get( 'wgUserLanguage' )
+               );
                this.$description.descriptionview( {
                        value: {
                                language: mw.config.get( 'wgUserLanguage' ),
                                description: this.$description.hasClass( 
'wb-empty' )
                                        ? null
                                        // FIXME: entity object should not 
contain fallback strings
-                                       : this.options.value.getDescription( 
mw.config.get( 'wgUserLanguage' ) )
+                                       : ( description && 
description.getText() )
                        },
                        helpMessage: mw.msg(
                                'wikibase-description-input-help-message',
@@ -171,10 +177,13 @@
                        this.$aliases = $( '<div/>' ).appendTo( this.element );
                }
 
+               var aliases = this.options.value.getFingerprint().getAliasesFor(
+                       mw.config.get( 'wgUserLanguage' )
+               );
                this.$aliases.aliasesview( {
                        value: {
                                language:  mw.config.get( 'wgUserLanguage' ),
-                               aliases: this.options.value.getAliases( 
mw.config.get( 'wgUserLanguage' ) )
+                               aliases: aliases && aliases.getTexts()
                        },
                        aliasesChanger: 
this.options.entityChangersFactory.getAliasesChanger()
                } );
@@ -203,14 +212,20 @@
                        this.$fingerprints = $( '<div/>' ).insertAfter( 
$precedingNode );
                }
 
-               var value = [];
+               var fingerprint = this.options.value.getFingerprint(),
+                       value = [],
+                       nextValue;
                for( var i = 0; i < this.options.languages.length; i++ ) {
-                       value.push( {
+                       nextValue = {
                                language: this.options.languages[i],
-                               label: this.options.value.getLabel( 
this.options.languages[i] ) || null,
-                               description: this.options.value.getDescription( 
this.options.languages[i] ) || null,
-                               aliases: this.options.value.getAliases( 
this.options.languages[i] ) || []
-                       } );
+                               label: fingerprint.getLabelFor( 
this.options.languages[i] ),
+                               description: fingerprint.getDescriptionFor( 
this.options.languages[i] ),
+                               aliases: fingerprint.getAliasesFor( 
this.options.languages[i] )
+                       };
+                       nextValue.label = nextValue.label ? 
nextValue.label.getText() : null;
+                       nextValue.description = nextValue.description ? 
nextValue.description.getText() : null;
+                       nextValue.aliases = nextValue.aliases ? 
nextValue.aliases.getTexts() : [];
+                       value.push( nextValue );
                }
 
                this.$fingerprints.fingerprintgroupview( {
@@ -229,7 +244,7 @@
 
                this.$claims
                .claimgrouplistview( {
-                       value: this.options.value.getClaims(),
+                       value: this.options.value.getStatements(),
                        entityType: this.options.value.getType(),
                        entityStore: this.options.entityStore,
                        valueViewBuilder: this.options.valueViewBuilder,
@@ -261,7 +276,8 @@
                                $sitelinklistview = $sitelinkgroupview.find( 
'.wikibase-sitelinklistview' ),
                                group = $sitelinkgroupview.data( 
'wb-sitelinks-group' ),
                                siteIdsOfGroup = [],
-                               siteLinks = self.options.value.getSiteLinks(),
+                               siteLinkSet = self.options.value.getSiteLinks(),
+                               siteLinkIds = siteLinkSet.getKeys(),
                                siteLinksOfGroup = [];
 
                        $sitelinklistview.find( '.wikibase-sitelinkview' 
).each( function() {
@@ -269,9 +285,9 @@
                        } );
 
                        for( var i = 0; i < siteIdsOfGroup.length; i++ ) {
-                               for( var j = 0; j < siteLinks.length; j++ ) {
-                                       if( siteLinks[j].getSiteId() === 
siteIdsOfGroup[i] ) {
-                                               siteLinksOfGroup.push( 
siteLinks[j] );
+                               for( var j = 0; j < siteLinkIds.length; j++ ) {
+                                       if( siteLinkIds[j] === 
siteIdsOfGroup[i] ) {
+                                               siteLinksOfGroup.push( 
siteLinkSet.getItemByKey( siteLinkIds[j] ) );
                                                break;
                                        }
                                }
diff --git a/lib/resources/jquery.wikibase/jquery.wikibase.referenceview.js 
b/lib/resources/jquery.wikibase/jquery.wikibase.referenceview.js
index 0d10b45..3ead314 100644
--- a/lib/resources/jquery.wikibase/jquery.wikibase.referenceview.js
+++ b/lib/resources/jquery.wikibase/jquery.wikibase.referenceview.js
@@ -298,9 +298,11 @@
                                snakList = new wb.datamodel.SnakList();
 
                        for( var i = 0; i < snaklistviews.length; i++ ) {
-                               var snak = 
this.options.listItemAdapter.liInstance( snaklistviews.eq( i ) ).value();
-                               if( snak ) {
-                                       snakList.add( snak );
+                               var curSnakList = 
this.options.listItemAdapter.liInstance(
+                                       snaklistviews.eq( i )
+                               ).value();
+                               if( curSnakList ) {
+                                       snakList.merge( curSnakList );
                                }
                        }
 
@@ -436,7 +438,7 @@
                                } else if ( !dropValue ) {
                                        // Gather all the current snaks in a 
single SnakList to set to reset the
                                        // initial qualifiers:
-                                       this._initialSnakList.add( 
snaklistview.value() );
+                                       this._initialSnakList.merge( 
snaklistview.value() );
                                }
                        }
                }
@@ -513,7 +515,7 @@
                        for( var i = 0; i < $snaklistviews.length; i++ ) {
                                var snakview = 
this.options.listItemAdapter.liInstance( $snaklistviews.eq( i ) );
                                if( snakview.value() ) {
-                                       snakList.add( snakview.value() );
+                                       snakList.merge( snakview.value() );
                                }
                        }
                }
diff --git a/lib/resources/jquery.wikibase/jquery.wikibase.snaklistview.js 
b/lib/resources/jquery.wikibase/jquery.wikibase.snaklistview.js
index 9f707cd..9b85eae 100644
--- a/lib/resources/jquery.wikibase/jquery.wikibase.snaklistview.js
+++ b/lib/resources/jquery.wikibase/jquery.wikibase.snaklistview.js
@@ -355,7 +355,7 @@
                        }
                } );
 
-               return ( snaks.length > 0 ) ? new wb.datamodel.SnakList( snaks 
): null;
+               return ( snaks.length > 0 ) ? new wb.datamodel.SnakList( snaks 
) : null;
        },
 
        /**
@@ -407,7 +407,7 @@
 
                $.each( this._listview.items(), function( i, item ) {
                        var snakview = self._lia.liInstance( $( item ) );
-                       snakList.addSnak( snakview.snak() );
+                       snakList.addItem( snakview.snak() );
                } );
 
                return this._snakList.equals( snakList );
diff --git a/lib/resources/jquery.wikibase/jquery.wikibase.statementview.js 
b/lib/resources/jquery.wikibase/jquery.wikibase.statementview.js
index 5b7620d..5630a15 100644
--- a/lib/resources/jquery.wikibase/jquery.wikibase.statementview.js
+++ b/lib/resources/jquery.wikibase/jquery.wikibase.statementview.js
@@ -146,14 +146,14 @@
                                listItemAdapter: new 
$.wikibase.listview.ListItemAdapter( {
                                        listItemWidget: 
$.wikibase.referenceview,
                                        newItemOptionsFn: function( value ) {
-                                               var index = indexOf( value, 
self.value().getReferences() );
+                                               var index = indexOf( value, 
self.value().getReferences().toArray() );
                                                if( index === null ) {
                                                        // The empty list view 
item for this is already appended to the list view
                                                        index = 
self._referencesListview.items().length - 1;
                                                }
                                                return {
                                                        value: value || null,
-                                                       statementGuid: 
self.value().getGuid(),
+                                                       statementGuid: 
self.value().getClaim().getGuid(),
                                                        index: index,
                                                        entityStore: 
self.option( 'entityStore' ),
                                                        valueViewBuilder: 
self.option( 'valueViewBuilder' ),
@@ -161,7 +161,7 @@
                                                };
                                        }
                                } ),
-                               value: refs
+                               value: refs.toArray()
                        } );
 
                        this._referencesListview = $listview.data( 'listview' );
@@ -246,7 +246,7 @@
                        helpMessage: this.option( 'helpMessage' ),
                        predefined: this.option( 'predefined' ),
                        locked: this.option( 'locked' ),
-                       value: statement,
+                       value: statement && statement.getClaim(),
                        valueViewBuilder: this.option( 'valueViewBuilder' )
                } );
 
@@ -363,11 +363,9 @@
                var claim = this._claimview._instantiateClaim( guid );
 
                return new wb.datamodel.Statement(
-                       claim.getMainSnak(),
-                       claim.getQualifiers(),
-                       this.getReferences(),
-                       this._rankSelector.rank(),
-                       guid
+                       claim,
+                       new wb.datamodel.ReferenceList( this.getReferences() ),
+                       this._rankSelector.rank()
                );
        },
 
@@ -429,7 +427,7 @@
                referenceview.disable();
 
                this._referencesChanger.removeReference(
-                       this.value().getGuid(),
+                       this.value().getClaim().getGuid(),
                        referenceview.value()
                )
                .done( function() {
@@ -573,13 +571,13 @@
                        guid;
 
                if( this.value() ) {
-                       guid = this.value().getGuid();
+                       guid = this.value().getClaim().getGuid();
                } else {
                        var guidGenerator = new 
wb.utilities.ClaimGuidGenerator();
                        guid = guidGenerator.newGuid( mw.config.get( 
'wbEntityId' ) );
                }
 
-               return this.option( 'claimsChanger' ).setClaim(
+               return this.option( 'claimsChanger' ).setStatement(
                        this._instantiateStatement( guid ),
                        this.option( 'index' )
                )
diff --git a/lib/resources/jquery.wikibase/snakview/resources.php 
b/lib/resources/jquery.wikibase/snakview/resources.php
index 11e053c..734e6c2 100644
--- a/lib/resources/jquery.wikibase/snakview/resources.php
+++ b/lib/resources/jquery.wikibase/snakview/resources.php
@@ -41,6 +41,8 @@
                                'mediawiki.legacy.shared',
                                'mw.config.values.wbRepo',
                                'wikibase.datamodel',
+                               'wikibase.serialization.SnakDeserializer',
+                               'wikibase.serialization.SnakSerializer',
                                'wikibase.utilities',
                        ),
                        'messages' => array(
@@ -104,6 +106,7 @@
                                'snakview.variations.Value.js',
                        ),
                        'dependencies' => array(
+                               'dataValues',
                                'jquery.wikibase.snakview.variations',
                                'jquery.wikibase.snakview.variations.Variation',
                                'wikibase.datamodel',
diff --git a/lib/resources/jquery.wikibase/snakview/snakview.js 
b/lib/resources/jquery.wikibase/snakview/snakview.js
index 8e07eee..3badefd 100644
--- a/lib/resources/jquery.wikibase/snakview/snakview.js
+++ b/lib/resources/jquery.wikibase/snakview/snakview.js
@@ -175,7 +175,6 @@
 
                this._cachedValues = {};
 
-               // set value, can be a wb.datamodel.Snak or plain Object as 
wb.datamodel.Snak.toMap() or just pieces of it
                this.value( this.option( 'value' ) || {} );
 
                if( this.option( 'autoStartEditing' ) && !this.snak() ) {
@@ -379,7 +378,7 @@
                        }
 
                        // update view; will remove edit interfaces and 
represent value statically
-                       this._setValue( newSnak !== null ? newSnak.toMap() : {} 
); // triggers this.draw()
+                       this._setValue( newSnak !== null ? this._serializeSnak( 
newSnak ) : {} ); // triggers this.draw()
                        // 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
@@ -495,7 +494,7 @@
         * @return {Object}
         */
        initialValue: function() {
-               return this.isInEditMode() ? this.initialSnak().toMap() : 
this._getValue();
+               return this.isInEditMode() ? this._serializeSnak( 
this.initialSnak() ) : this._getValue();
        },
 
        /**
@@ -527,7 +526,16 @@
                        throw new Error( 'The given value has to be a plain 
object, an instance of' +
                                ' wikibase.datamodel.Snak, or null' );
                }
-               this._setValue( ( value instanceof wb.datamodel.Snak ) ? 
value.toMap() : value );
+               this._setValue( ( value instanceof wb.datamodel.Snak ) ? 
this._serializeSnak( value ) : value );
+       },
+
+       /**
+        * @param {wikibase.datamodel.Snak} value
+        * @return {Object}
+        */
+       _serializeSnak: function( snak ) {
+               var snakSerializer = new 
wikibase.serialization.SnakSerializer();
+               return snakSerializer.serialize( snak );
        },
 
        /**
@@ -551,7 +559,7 @@
 
        /**
         * Will update the view to represent a given Snak in form of a plain 
Object. The given object
-        * can have all fields - or a subset of fields - 
wb.datamodel.Snak.toMap() would return.
+        * can have all fields - or a subset of fields - a serialized 
wb.datamodel.Snak would have.
         *
         * @since 0.4
         *
@@ -607,7 +615,14 @@
                        // TODO: variations should have a function to ask 
whether fully defined yet
                        try{
                                // NOTE: can still be null if user didn't enter 
essential information in variation's UI
-                               return wb.datamodel.Snak.newFromMap( 
this.value() );
+                               var value = this.value();
+                               if( value.datavalue ) {
+                                       value.datavalue = {
+                                               type: value.datavalue.getType(),
+                                               value: value.datavalue.toJSON()
+                                       };
+                               }
+                               return ( new 
wb.serialization.SnakDeserializer() ).deserialize( value );
                        } catch( e ) {
                                return null;
                        }
diff --git 
a/lib/resources/jquery.wikibase/snakview/snakview.variations.Value.js 
b/lib/resources/jquery.wikibase/snakview/snakview.variations.Value.js
index 2279b44..585a776 100644
--- a/lib/resources/jquery.wikibase/snakview/snakview.variations.Value.js
+++ b/lib/resources/jquery.wikibase/snakview/snakview.variations.Value.js
@@ -2,7 +2,7 @@
  * @licence GNU GPL v2+
  * @author Daniel Werner < daniel.wer...@wikimedia.de >
  */
-( function( mw, wb, $, dataTypeStore ) {
+( function( mw, wb, $, dataTypeStore, dv ) {
        'use strict';
 
        var MODULE = $.wikibase.snakview.variations,
@@ -48,7 +48,10 @@
                 * @see jQuery.wikibase.snakview.variations.Variation._setValue
                 */
                _setValue: function( value ) {
-                       this._newDataValue = value.datavalue || null;
+                       this._newDataValue = null;
+                       if( value.datavalue ) {
+                               this._newDataValue = dv.newDataValue( 
value.datavalue.type, value.datavalue.value );
+                       }
                },
 
                /**
@@ -160,7 +163,7 @@
                                        // happen if a property got deleted but 
the Snaks using it didn't change the
                                        // property.
                                        var dataTypeId = fetchedProperty
-                                               ? 
fetchedProperty.getContent().getDataType()
+                                               ? 
fetchedProperty.getContent().getDataTypeId()
                                                : false;
                                        var dataType = false;
 
@@ -362,4 +365,4 @@
                }
        } );
 
-}( mediaWiki, wikibase, jQuery, wikibase.dataTypes ) );
+}( mediaWiki, wikibase, jQuery, wikibase.dataTypes, dataValues ) );
diff --git a/lib/resources/wikibase.store/resources.php 
b/lib/resources/wikibase.store/resources.php
index a250fba..570836e 100644
--- a/lib/resources/wikibase.store/resources.php
+++ b/lib/resources/wikibase.store/resources.php
@@ -67,7 +67,7 @@
                        'dependencies' => array(
                                'mediawiki.Title',
                                'util.inherit',
-                               'wikibase.serialization', // For registering in 
the SerializerFactory
+                               'wikibase.serialization.Deserializer',
                                'wikibase.store',
                                'wikibase.store.FetchedContent',
                        ),
diff --git a/lib/resources/wikibase.store/store.ApiEntityStore.js 
b/lib/resources/wikibase.store/store.ApiEntityStore.js
index f8ea4de..4de7e72 100644
--- a/lib/resources/wikibase.store/store.ApiEntityStore.js
+++ b/lib/resources/wikibase.store/store.ApiEntityStore.js
@@ -75,7 +75,7 @@
                                                        return; // missing 
entity
                                                }
 
-                                               var entity = 
self._fetchedEntityUnserializer.unserialize( {
+                                               var entity = 
self._fetchedEntityUnserializer.deserialize( {
                                                        title: entityData.title,
                                                        content: entityData
                                                } );
diff --git a/lib/resources/wikibase.store/store.FetchedContentUnserializer.js 
b/lib/resources/wikibase.store/store.FetchedContentUnserializer.js
index ada8061..d363caa 100644
--- a/lib/resources/wikibase.store/store.FetchedContentUnserializer.js
+++ b/lib/resources/wikibase.store/store.FetchedContentUnserializer.js
@@ -5,34 +5,43 @@
 ( function( mw, wb, util ) {
        'use strict';
 
-       var PARENT = wb.serialization.Unserializer;
+       var PARENT = wb.serialization.Deserializer;
 
        /**
-        * Unserializer for Property entities.
+        * Deserializer for Property entities.
         *
-        * @option contentUnserializer {wb.serialization.Unserializer} The 
unserializer which should be
-        *         used to unserialize the actual content of the final 
FetchedContent object. If this
-        *         is not set, the content will be a string taken from the 
serialized data.
+        * @param {wikibase.serialization.Deserializer} [contentDeserializer]
+        *        The deserializer which should be used to deserialize the 
actual content of the final
+        *        FetchedContent object. If this is not set, the content will 
be a string taken from the
+        *        serialized data.
         *
         * @constructor
-        * @extends wb.Unserializer
+        * @extends wikibase.serialization.Deserializer
         * @since 0.4
         */
-       var SELF =
-               wb.store.FetchedContentUnserializer =
-                       util.inherit( 'WbFetchedContentUnserializer', PARENT, {
+       wb.store.FetchedContentUnserializer = util.inherit(
+               'WbFetchedContentUnserializer',
+               PARENT,
+               function( contentDeserializer ) {
+                       this._contentDeserializer = contentDeserializer;
+               }, {
+
                /**
-                * @see wb.serialization.Unserializer.unserialize
+                * @type {wikibase.serialization.Deserializer|null}
+                */
+               _contentDeserializer: null,
+
+               /**
+                * @see wikibase.serialization.Deserializer.deserialize
                 *
                 * @return {wikibase.store.FetchedContent}
                 */
-               unserialize: function( serialization ) {
-                       var title = new mw.Title( serialization.title ),
-                               contentUnserializer = 
this._options.contentUnserializer;
+               deserialize: function( serialization ) {
+                       var title = new mw.Title( serialization.title );
 
-                       // If content unserializer option is not given, take 
plain content value.
-                       var content = contentUnserializer
-                               ? contentUnserializer.unserialize( 
serialization.content )
+                       // If content deserializer is not given, take plain 
content value.
+                       var content = this._contentDeserializer
+                               ? this._contentDeserializer.deserialize( 
serialization.content )
                                : serialization.content;
 
                        return new wb.store.FetchedContent( {
@@ -41,8 +50,5 @@
                        } );
                }
        } );
-
-       // register in SerializationFactory for wb.store.FetchedContent 
unserialization handling:
-       wb.serialization.SerializerFactory.registerUnserializer( SELF, 
wb.store.FetchedContent );
 
 }( mediaWiki, wikibase, util ) );
diff --git a/lib/resources/wikibase.store/store.MwConfigEntityStore.js 
b/lib/resources/wikibase.store/store.MwConfigEntityStore.js
index 9539b1b..97651bb 100644
--- a/lib/resources/wikibase.store/store.MwConfigEntityStore.js
+++ b/lib/resources/wikibase.store/store.MwConfigEntityStore.js
@@ -44,7 +44,7 @@
                                deferred.reject();
                        } else {
                                if( !( this._fetchedEntities[entityId] 
instanceof MODULE.FetchedContent ) ) {
-                                       this._fetchedEntities[entityId] = 
this._fetchedEntityUnserializer.unserialize(
+                                       this._fetchedEntities[entityId] = 
this._fetchedEntityUnserializer.deserialize(
                                                this._fetchedEntities[entityId]
                                        );
                                }
diff --git a/lib/resources/wikibase.utilities/wikibase.utilities.ui.js 
b/lib/resources/wikibase.utilities/wikibase.utilities.ui.js
index cd585e6..aed9964 100644
--- a/lib/resources/wikibase.utilities/wikibase.utilities.ui.js
+++ b/lib/resources/wikibase.utilities/wikibase.utilities.ui.js
@@ -48,6 +48,15 @@
        };
 
        /**
+        * @param {wikibase.datamodel.Entity} entity
+        * @return {string|null}
+        */
+       function getEntityLabelForUserLang( entity ) {
+               var term = entity.getFingerprint().getLabelFor( mw.config.get( 
'wgUserLanguage' ) );
+               return term && term.getText();
+       }
+
+       /**
         * Creates a pretty label for an Entity. This means if the Entity 
doesn't actually have a label,
         * some alternative information will be shown (the ID + some 
information that the label is not
         * set).
@@ -58,7 +67,7 @@
         * @return {jQuery} Construct of one or many HTML elements
         */
        wb.utilities.ui.buildPrettyEntityLabel = function( entity ) {
-               var label = entity.getLabel(),
+               var label = getEntityLabelForUserLang( entity ),
                        text = wb.utilities.ui.buildPrettyEntityLabelText( 
entity ),
                        $label = $( document.createTextNode( text ) );
 
@@ -86,7 +95,7 @@
         * @return {string} Either the label, ID or empty string
         */
        wb.utilities.ui.buildPrettyEntityLabelText = function( entity ) {
-               return entity && ( entity.getLabel() || entity.getId() ) || '';
+               return entity && ( getEntityLabelForUserLang( entity ) || 
entity.getId() ) || '';
        };
 
        /**
diff --git a/lib/tests/qunit/entityChangers/AliasesChanger.tests.js 
b/lib/tests/qunit/entityChangers/AliasesChanger.tests.js
index 16d3955..9e9f0f1 100644
--- a/lib/tests/qunit/entityChangers/AliasesChanger.tests.js
+++ b/lib/tests/qunit/entityChangers/AliasesChanger.tests.js
@@ -30,7 +30,7 @@
                var aliasesChanger = new SUBJECT(
                        api,
                        { getAliasesRevision: function() { return 0; } },
-                       new wb.datamodel.Item()
+                       new wb.datamodel.Item( 'Q1' )
                );
 
                aliasesChanger.setAliases(
@@ -55,7 +55,7 @@
                                getAliasesRevision: function() { return 0; },
                                setAliasesRevision: function() {}
                        },
-                       new wb.datamodel.Item()
+                       new wb.datamodel.Item( 'Q1' )
                );
 
                QUnit.stop();
@@ -87,7 +87,7 @@
                                getAliasesRevision: function() { return 0; },
                                setAliasesRevision: function() {}
                        },
-                       new wb.datamodel.Item()
+                       new wb.datamodel.Item( 'Q1' )
                );
 
                QUnit.stop();
@@ -111,4 +111,56 @@
                } );
        } );
 
+       QUnit.test( 'setAliases correctly removes aliases', function( assert ) {
+               var api = {
+                       setAliases: sinon.spy( function() {
+                               return $.Deferred().resolve( {
+                                       entity: {}
+                               } ).promise();
+                       } )
+               };
+               var item = new wb.datamodel.Item( 'Q1', new 
wb.datamodel.Fingerprint(
+                       null,
+                       null,
+                       new wb.datamodel.MultiTermMap( { language: new 
wb.datamodel.MultiTerm( 'language', [ 'alias' ] ) } )
+               ) );
+               var aliasesChanger = new SUBJECT(
+                       api,
+                       {
+                               getAliasesRevision: function() { return 0; },
+                               setAliasesRevision: function() {}
+                       },
+                       item
+               );
+
+               QUnit.stop();
+
+               aliasesChanger.setAliases(
+                       [],
+                       'language'
+               )
+               .done( function() {
+                       QUnit.start();
+
+                       assert.ok( true, 'setAliases succeeded' );
+
+                       assert.ok(
+                               item.getFingerprint().getAliasesFor( 'language' 
).isEmpty(),
+                               'Verified aliases being empty.'
+                       );
+
+                       sinon.assert.calledWith(
+                               api.setAliases,
+                               'Q1',
+                               0,
+                               sinon.match( [] ),
+                               sinon.match( [ 'alias' ] ),
+                               'language'
+                       );
+               } )
+               .fail( function() {
+                       assert.ok( false, 'setAliases failed' );
+               } );
+       } );
+
 } )( sinon, wikibase, jQuery );
diff --git a/lib/tests/qunit/entityChangers/ClaimsChanger.tests.js 
b/lib/tests/qunit/entityChangers/ClaimsChanger.tests.js
index b23747d..8713052 100644
--- a/lib/tests/qunit/entityChangers/ClaimsChanger.tests.js
+++ b/lib/tests/qunit/entityChangers/ClaimsChanger.tests.js
@@ -21,7 +21,7 @@
                assert.ok( new SUBJECT() instanceof SUBJECT );
        } );
 
-       QUnit.test( 'removeClaim performs correct API call', function( assert ) 
{
+       QUnit.test( 'removeStatement performs correct API call', function( 
assert ) {
                var api = {
                        removeClaim: sinon.spy( function() {
                                return $.Deferred().promise();
@@ -33,15 +33,17 @@
                        'entity'
                );
 
-               claimsChanger.removeClaim(
-                       new wb.datamodel.Claim( new 
wb.datamodel.PropertyNoValueSnak( 'P1' ) ),
+               claimsChanger.removeStatement(
+                       new wb.datamodel.Statement( new wb.datamodel.Claim(
+                               new wb.datamodel.PropertyNoValueSnak( 'P1' )
+                       ) ),
                        'index'
                );
 
                assert.ok( api.removeClaim.calledOnce );
        } );
 
-       QUnit.test( 'removeClaim correctly handles API response', function( 
assert ) {
+       QUnit.test( 'removeStatement correctly handles API response', function( 
assert ) {
                var api = {
                        removeClaim: sinon.spy( function() {
                                return $.Deferred().resolve( {
@@ -61,20 +63,24 @@
 
                QUnit.stop();
 
-               claimsChanger.removeClaim(
-                       new wb.datamodel.Claim( new 
wb.datamodel.PropertyNoValueSnak( 'P1' ) ),
+               claimsChanger.removeStatement(
+                       new wb.datamodel.Statement( new wb.datamodel.Claim(
+                               new wb.datamodel.PropertyNoValueSnak( 'P1' )
+                       ) ),
                        'index'
                )
                .done( function() {
-                       QUnit.start();
-                       assert.ok( true, 'removeClaim succeeded' );
+                       assert.ok( true, 'removeStatement succeeded' );
                } )
                .fail( function() {
-                       assert.ok( false, 'removeClaim failed' );
+                       assert.ok( false, 'removeStatement failed' );
+               } )
+               .always( function() {
+                       QUnit.start();
                } );
        } );
 
-       QUnit.test( 'removeClaim correctly handles API failures', function( 
assert ) {
+       QUnit.test( 'removeStatement correctly handles API failures', function( 
assert ) {
                var api = {
                        removeClaim: sinon.spy( function() {
                                return $.Deferred()
@@ -93,22 +99,25 @@
 
                QUnit.stop();
 
-               claimsChanger.removeClaim(
-                       new wb.datamodel.Claim( new 
wb.datamodel.PropertyNoValueSnak( 'P1' ) ),
+               claimsChanger.removeStatement(
+                       new wb.datamodel.Statement( new wb.datamodel.Claim(
+                               new wb.datamodel.PropertyNoValueSnak( 'P1' )
+                       ) ),
                        'index'
                )
                .done( function() {
-                       assert.ok( false, 'removeClaim should have failed' );
+                       assert.ok( false, 'removeStatement should have failed' 
);
                } )
                .fail( function( error ) {
-                       QUnit.start();
-
                        assert.ok(
                                error instanceof wb.RepoApiError,
-                               'removeClaim did not fail with a RepoApiError'
+                               'removeStatement did not fail with a 
RepoApiError'
                        );
 
                        assert.equal( error.code, 'errorCode' );
+               } )
+               .always( function() {
+                       QUnit.start();
                } );
        } );
 
@@ -121,7 +130,8 @@
                var claimsChanger = new SUBJECT(
                        api,
                        { getClaimRevision: function() { return 0; } },
-                       'entity'
+                       'entity',
+                       new wb.serialization.ClaimSerializer()
                );
 
                claimsChanger.setClaim(
@@ -144,7 +154,9 @@
                var claimsChanger = new SUBJECT(
                        api,
                        { getClaimRevision: function() { return 0; }, 
setClaimRevision: function() {} },
-                       'entity'
+                       'entity',
+                       new wb.serialization.ClaimSerializer(),
+                       new wb.serialization.ClaimDeserializer()
                );
 
                QUnit.stop();
@@ -154,8 +166,6 @@
                        'index'
                )
                .done( function( savedClaim ) {
-                       QUnit.start();
-
                        assert.ok(
                                savedClaim instanceof wb.datamodel.Claim,
                                'setClaim did not resolve with a Claim'
@@ -163,6 +173,9 @@
                } )
                .fail( function() {
                        assert.ok( false, 'setClaim failed' );
+               } )
+               .always( function() {
+                       QUnit.start();
                } );
        } );
 
@@ -180,7 +193,9 @@
                                getClaimRevision: function() { return 0; },
                                setClaimRevision: function() {}
                        },
-                       'entity'
+                       'entity',
+                       new wb.serialization.ClaimSerializer(),
+                       new wb.serialization.ClaimDeserializer()
                );
 
                QUnit.stop();
@@ -193,14 +208,129 @@
                        assert.ok( false, 'setClaim should have failed' );
                } )
                .fail( function( error ) {
-                       QUnit.start();
-
                        assert.ok(
                                error instanceof wb.RepoApiError,
                                'setClaim failed with a RepoApiError'
                        );
 
                        assert.equal( error.code, 'errorCode' );
+               } )
+               .always( function() {
+                       QUnit.start();
+               } );
+       } );
+
+       QUnit.test( 'setStatement performs correct API call', function( assert 
) {
+               var api = {
+                       setClaim: sinon.spy( function() {
+                               return $.Deferred().promise();
+                       } )
+               };
+               var claimsChanger = new SUBJECT(
+                       api,
+                       { getClaimRevision: function() { return 0; } },
+                       'entity',
+                       null,
+                       null,
+                       new wb.serialization.StatementSerializer()
+               );
+
+               claimsChanger.setStatement(
+                       new wb.datamodel.Statement( new wb.datamodel.Claim(
+                               new wb.datamodel.PropertyNoValueSnak( 'P1' )
+                       ) ),
+                       'index'
+               );
+
+               assert.ok( api.setClaim.calledOnce );
+       } );
+
+       QUnit.test( 'setStatement correctly handles API response', function( 
assert ) {
+               var api = {
+                       setClaim: sinon.spy( function() {
+                               return $.Deferred().resolve( {
+                                       claim: {
+                                               mainsnak: { snaktype: 
'novalue', property: 'P1' },
+                                               rank: 'normal'
+                                       },
+                                       pageinfo: {}
+                               } ).promise();
+                       } )
+               };
+               var claimsChanger = new SUBJECT(
+                       api,
+                       { getClaimRevision: function() { return 0; }, 
setClaimRevision: function() {} },
+                       'entity',
+                       null,
+                       null,
+                       new wb.serialization.StatementSerializer(),
+                       new wb.serialization.StatementDeserializer()
+               );
+
+               QUnit.stop();
+
+               claimsChanger.setStatement(
+                       new wb.datamodel.Statement( new wb.datamodel.Claim(
+                               new wb.datamodel.PropertyNoValueSnak( 'P1' )
+                       ) ),
+                       'index'
+               )
+               .done( function( savedStatement ) {
+                       assert.ok(
+                               savedStatement instanceof 
wb.datamodel.Statement,
+                               'setStatement did not resolve with a Statement'
+                       );
+               } )
+               .fail( function() {
+                       assert.ok( false, 'setStatement failed' );
+               } )
+               .always( function() {
+                       QUnit.start();
+               } );
+       } );
+
+       QUnit.test( 'setStatement correctly handles API failures', function( 
assert ) {
+               var api = {
+                       setClaim: sinon.spy( function() {
+                               return $.Deferred()
+                                       .reject( 'errorCode', { error: { code: 
'errorCode' } } )
+                                       .promise();
+                       } )
+               };
+               var claimsChanger = new SUBJECT(
+                       api,
+                       {
+                               getClaimRevision: function() { return 0; },
+                               setClaimRevision: function() {}
+                       },
+                       'entity',
+                       null,
+                       null,
+                       new wb.serialization.StatementSerializer(),
+                       new wb.serialization.StatementDeserializer()
+               );
+
+               QUnit.stop();
+
+               claimsChanger.setStatement(
+                       new wb.datamodel.Statement( new wb.datamodel.Claim(
+                               new wb.datamodel.PropertyNoValueSnak( 'P1' )
+                       ) ),
+                       'index'
+               )
+               .done( function( savedStatement ) {
+                       assert.ok( false, 'setStatement should have failed' );
+               } )
+               .fail( function( error ) {
+                       assert.ok(
+                               error instanceof wb.RepoApiError,
+                               'setStatement failed with a RepoApiError'
+                       );
+
+                       assert.equal( error.code, 'errorCode' );
+               } )
+               .always( function() {
+                       QUnit.start();
                } );
        } );
 
diff --git a/lib/tests/qunit/entityChangers/DescriptionsChanger.tests.js 
b/lib/tests/qunit/entityChangers/DescriptionsChanger.tests.js
index 6f4b440..7fab678 100644
--- a/lib/tests/qunit/entityChangers/DescriptionsChanger.tests.js
+++ b/lib/tests/qunit/entityChangers/DescriptionsChanger.tests.js
@@ -30,7 +30,7 @@
                var descriptionsChanger = new SUBJECT(
                        api,
                        { getDescriptionRevision: function() { return 0; } },
-                       new wb.datamodel.Item()
+                       new wb.datamodel.Item( 'Q1' )
                );
 
                descriptionsChanger.setDescription( 'description', 'language' );
@@ -56,7 +56,7 @@
                var descriptionsChanger = new SUBJECT(
                        api,
                        { getDescriptionRevision: function() { return 0; }, 
setDescriptionRevision: function() {} },
-                       new wb.datamodel.Item()
+                       new wb.datamodel.Item( 'Q1' )
                );
 
                QUnit.stop();
@@ -80,7 +80,7 @@
                var descriptionsChanger = new SUBJECT(
                        api,
                        { getDescriptionRevision: function() { return 0; }, 
setDescriptionRevision: function() {} },
-                       new wb.datamodel.Item()
+                       new wb.datamodel.Item( 'Q1' )
                );
 
                QUnit.stop();
diff --git a/lib/tests/qunit/entityChangers/LabelsChanger.tests.js 
b/lib/tests/qunit/entityChangers/LabelsChanger.tests.js
index c7c8f57..eca8024 100644
--- a/lib/tests/qunit/entityChangers/LabelsChanger.tests.js
+++ b/lib/tests/qunit/entityChangers/LabelsChanger.tests.js
@@ -30,7 +30,7 @@
                var labelsChanger = new SUBJECT(
                        api,
                        { getLabelRevision: function() { return 0; } },
-                       new wb.datamodel.Item()
+                       new wb.datamodel.Item( 'Q1' )
                );
 
                labelsChanger.setLabel( 'label', 'language' );
@@ -56,7 +56,7 @@
                var labelsChanger = new SUBJECT(
                        api,
                        { getLabelRevision: function() { return 0; }, 
setLabelRevision: function() {} },
-                       new wb.datamodel.Item()
+                       new wb.datamodel.Item( 'Q1' )
                );
 
                QUnit.stop();
@@ -80,7 +80,7 @@
                var labelsChanger = new SUBJECT(
                        api,
                        { getLabelRevision: function() { return 0; }, 
setLabelRevision: function() {} },
-                       new wb.datamodel.Item()
+                       new wb.datamodel.Item( 'Q1' )
                );
 
                QUnit.stop();
diff --git a/lib/tests/qunit/entityChangers/ReferencesChanger.tests.js 
b/lib/tests/qunit/entityChangers/ReferencesChanger.tests.js
index e85316a..893b583 100644
--- a/lib/tests/qunit/entityChangers/ReferencesChanger.tests.js
+++ b/lib/tests/qunit/entityChangers/ReferencesChanger.tests.js
@@ -123,7 +123,8 @@
                var referencesChanger = new SUBJECT(
                        api,
                        { getClaimRevision: function() { return 0; } },
-                       'entity'
+                       'entity',
+                       new wb.serialization.ReferenceSerializer()
                );
 
                referencesChanger.setReference(
@@ -147,7 +148,9 @@
                var referencesChanger = new SUBJECT(
                        api,
                        { getClaimRevision: function() { return 0; }, 
setClaimRevision: function() {} },
-                       'entity'
+                       'entity',
+                       new wb.serialization.ReferenceSerializer(),
+                       new wb.serialization.ReferenceDeserializer()
                );
 
                QUnit.stop();
@@ -180,7 +183,8 @@
                                getClaimRevision: function() { return 0; },
                                setClaimRevision: function() {}
                        },
-                       'entity'
+                       'entity',
+                       new wb.serialization.ReferenceSerializer()
                );
 
                QUnit.stop();
diff --git a/lib/tests/qunit/entityChangers/SiteLinksChanger.tests.js 
b/lib/tests/qunit/entityChangers/SiteLinksChanger.tests.js
index 2c384fa..0803a9e 100644
--- a/lib/tests/qunit/entityChangers/SiteLinksChanger.tests.js
+++ b/lib/tests/qunit/entityChangers/SiteLinksChanger.tests.js
@@ -30,7 +30,7 @@
                var siteLinksChanger = new SUBJECT(
                        api,
                        { getSitelinksRevision: function() { return 0; } },
-                       new wb.datamodel.Item()
+                       new wb.datamodel.Item( 'Q1' )
                );
 
                siteLinksChanger.setSiteLink( new wb.datamodel.SiteLink( 
'siteId', 'pageName' ) );
@@ -56,7 +56,7 @@
                var siteLinksChanger = new SUBJECT(
                        api,
                        { getSitelinksRevision: function() { return 0; }, 
setSitelinksRevision: function() {} },
-                       new wb.datamodel.Item()
+                       new wb.datamodel.Item( 'Q1' )
                );
 
                QUnit.stop();
@@ -80,7 +80,7 @@
                var siteLinksChanger = new SUBJECT(
                        api,
                        { getSitelinksRevision: function() { return 0; }, 
setSitelinksRevision: function() {} },
-                       new wb.datamodel.Item()
+                       new wb.datamodel.Item( 'Q1' )
                );
 
                QUnit.stop();
diff --git a/lib/tests/qunit/entityChangers/resources.php 
b/lib/tests/qunit/entityChangers/resources.php
index 5b53e3d..95e5522 100644
--- a/lib/tests/qunit/entityChangers/resources.php
+++ b/lib/tests/qunit/entityChangers/resources.php
@@ -32,6 +32,10 @@
                        'dependencies' => array(
                                'wikibase.datamodel',
                                'wikibase.entityChangers.ClaimsChanger',
+                               'wikibase.serialization.ClaimDeserializer',
+                               'wikibase.serialization.ClaimSerializer',
+                               'wikibase.serialization.StatementDeserializer',
+                               'wikibase.serialization.StatementSerializer',
                        ),
                ),
 
@@ -62,6 +66,8 @@
                        'dependencies' => array(
                                'wikibase.datamodel',
                                'wikibase.entityChangers.ReferencesChanger',
+                               'wikibase.serialization.ReferenceDeserializer',
+                               'wikibase.serialization.ReferenceSerializer',
                        ),
                ),
 
diff --git 
a/lib/tests/qunit/jquery.wikibase/jquery.wikibase.badgeselector.tests.js 
b/lib/tests/qunit/jquery.wikibase/jquery.wikibase.badgeselector.tests.js
index b02a3cc..3fb9c75 100644
--- a/lib/tests/qunit/jquery.wikibase/jquery.wikibase.badgeselector.tests.js
+++ b/lib/tests/qunit/jquery.wikibase/jquery.wikibase.badgeselector.tests.js
@@ -21,27 +21,27 @@
 var entities =  {
        Q1: new wb.store.FetchedContent( {
                title: new mw.Title( 'Item:Q1' ),
-               content: new wb.datamodel.Item( {
-                       id: 'Q1',
-                       type: 'item',
-                       labels: { en: { language: 'en', value: 'Q1-label' } }
-               } )
+               content: new wb.datamodel.Item( 'Q1',
+                       new wb.datamodel.Fingerprint( new wb.datamodel.TermMap( 
[
+                               new wb.datamodel.Term( 'en', 'Q1-label' )
+                       ] ) )
+               )
        } ),
        Q2: new wb.store.FetchedContent( {
                title: new mw.Title( 'Item:Q2' ),
-               content: new wb.datamodel.Item( {
-                       id: 'Q2',
-                       type: 'item',
-                       labels: { en: { language: 'en', value: 'Q2-label' } }
-               } )
+               content: new wb.datamodel.Item( 'Q2',
+                       new wb.datamodel.Fingerprint( new wb.datamodel.TermMap( 
[
+                               new wb.datamodel.Term( 'en', 'Q2-label' )
+                       ] ) )
+               )
        } ),
        Q3: new wb.store.FetchedContent( {
                title: new mw.Title( 'Item:Q3' ),
-               content: new wb.datamodel.Item( {
-                       id: 'Q3',
-                       type: 'item',
-                       labels: { en: { language: 'en', value: 'Q3-label' } }
-               } )
+               content: new wb.datamodel.Item( 'Q3',
+                       new wb.datamodel.Fingerprint( new wb.datamodel.TermMap( 
[
+                               new wb.datamodel.Term( 'en', 'Q3-label' )
+                       ] ) )
+               )
        } )
 };
 
diff --git 
a/lib/tests/qunit/jquery.wikibase/jquery.wikibase.claimgrouplistview.tests.js 
b/lib/tests/qunit/jquery.wikibase/jquery.wikibase.claimgrouplistview.tests.js
new file mode 100644
index 0000000..2d42325
--- /dev/null
+++ 
b/lib/tests/qunit/jquery.wikibase/jquery.wikibase.claimgrouplistview.tests.js
@@ -0,0 +1,132 @@
+/**
+ * @licence GNU GPL v2+
+ * @author Adrian Lang <adrian.l...@wikimedia.de>
+ */
+
+( function( $, wb, QUnit ) {
+'use strict';
+
+/**
+ * @param {Object} [options]
+ * @param {jQuery} [$node]
+ * @return {jQuery}
+ */
+var createClaimgrouplistview = function( options, $node ) {
+       options = $.extend( {
+               entityChangersFactory: {
+                       getClaimsChanger: function() {
+                               return 'i am a ClaimsChanger';
+                       },
+                       getReferencesChanger: function() {
+                               return null;
+                       }
+               },
+               entityStore: {
+                       get: function () {
+                               return $.Deferred().resolve().promise();
+                       }
+               },
+               api: 'i am an api',
+               valueViewBuilder: 'i am a ValueViewBuilder'
+       }, options || {} );
+
+       $node = $node || $( '<div/>' ).appendTo( 'body' );
+
+       return $node
+               .addClass( 'test_claimgrouplistview' )
+               .claimgrouplistview( options );
+};
+
+QUnit.module( 'jquery.wikibase.claimgrouplistview', QUnit.newMwEnvironment( {
+       teardown: function() {
+               $( '.test_claimgrouplistview' ).each( function() {
+                       var $claimgrouplistview = $( this ),
+                               claimgrouplistview = $claimgrouplistview.data( 
'claimgrouplistview' );
+
+                       if( claimgrouplistview ) {
+                               claimgrouplistview.destroy();
+                       }
+
+                       $claimgrouplistview.remove();
+               } );
+       }
+} ) );
+
+QUnit.test( 'Create & destroy', function( assert ) {
+       var $claimgrouplistview = createClaimgrouplistview(),
+               claimgrouplistview = $claimgrouplistview.data( 
'claimgrouplistview' );
+
+       assert.ok(
+               claimgrouplistview instanceof $.wikibase.claimgrouplistview,
+               'Created widget.'
+       );
+
+       claimgrouplistview.destroy();
+
+       assert.ok(
+               $claimgrouplistview.data( 'claimgrouplistview' ) === undefined,
+               'Destroyed widget.'
+       );
+
+       $claimgrouplistview = createClaimgrouplistview( {
+               value: new wb.datamodel.ClaimGroupSet( [
+                       new wb.datamodel.ClaimGroup( 'P1', new 
wb.datamodel.ClaimList() )
+               ] )
+       } );
+       claimgrouplistview = $claimgrouplistview.data( 'claimgrouplistview' );
+
+       assert.ok(
+               claimgrouplistview instanceof $.wikibase.claimgrouplistview,
+               'Created widget with wb.datamodel.ClaimGroupSet instance.'
+       );
+} );
+
+QUnit.test( 'enterNewItem', function( assert ) {
+       var $claimgrouplistview = createClaimgrouplistview(),
+               claimgrouplistview = $claimgrouplistview.data( 
'claimgrouplistview' );
+
+       assert.equal(
+               claimgrouplistview.listview().items().length,
+               0,
+               'Plain widget has no items.'
+       );
+
+       claimgrouplistview.enterNewItem();
+
+       assert.equal(
+               claimgrouplistview.listview().items().length,
+               1,
+               'Increased number of items after calling enterNewItem().'
+       );
+} );
+
+QUnit.test( 'enterNewItem & save', function( assert ) {
+       var $claimgrouplistview = createClaimgrouplistview(),
+               claimgrouplistview = $claimgrouplistview.data( 
'claimgrouplistview' );
+
+       claimgrouplistview.enterNewItem();
+
+       var $claimlistview = claimgrouplistview.listview().items().eq( 0 );
+
+       // Ugly hack to set the statementview value
+       $claimlistview.find( ':wikibase-statementview' ).data( 'statementview' 
)._statement
+               = new wb.datamodel.Statement(
+                       new wb.datamodel.Claim( new 
wb.datamodel.PropertyNoValueSnak( 'P1' ) )
+               );
+
+       assert.equal(
+               $claimlistview.hasClass( 'wb-new' ),
+               true,
+               'Verified claimlistview widget being pending.'
+       );
+
+       $claimlistview.data( 'claimlistview' )._trigger( 'afterstopediting', 
null, [ false ] );
+
+       assert.equal(
+               claimgrouplistview.listview().items().eq( 0 ).hasClass( 
'wb-new' ),
+               false,
+               'Verified new list item not being pending after saving.'
+       );
+} );
+
+}( jQuery, wikibase, QUnit ) );
diff --git a/lib/tests/qunit/jquery.wikibase/jquery.wikibase.claimview.tests.js 
b/lib/tests/qunit/jquery.wikibase/jquery.wikibase.claimview.tests.js
index 1a5b083..21e121b 100644
--- a/lib/tests/qunit/jquery.wikibase/jquery.wikibase.claimview.tests.js
+++ b/lib/tests/qunit/jquery.wikibase/jquery.wikibase.claimview.tests.js
@@ -9,12 +9,13 @@
                get: function() {
                        return $.Deferred().resolve( new 
wb.store.FetchedContent( {
                                title: new mw.Title( 'Property:P1' ),
-                               content: new wb.datamodel.Property( {
-                                       id: 'P1',
-                                       type: 'property',
-                                       datatype: 'string',
-                                       label: { en: 'P1' }
-                               } )
+                               content: new wb.datamodel.Property(
+                                       'P1',
+                                       'string',
+                                       new wb.datamodel.Fingerprint( new 
wb.datamodel.TermMap( [
+                                               new wb.datamodel.Term( 'en', 
'P1' )
+                                       ] ) )
+                               )
                        } ) );
                }
        };
@@ -59,6 +60,25 @@
                );
        } );
 
+       QUnit.test( 'Initialize and destroy claimview with value', function( 
assert ) {
+               var $node = createClaimview(
+                               new wb.datamodel.Claim( new 
wb.datamodel.PropertyNoValueSnak( 'P1' ) )
+                       ),
+                       claimview = $node.data( 'claimview' );
+
+               assert.ok(
+                       claimview instanceof $.wikibase.claimview,
+                       'Initialized claimview widget.'
+               );
+
+               claimview.destroy();
+
+               assert.ok(
+                       $node.data( 'listview' ) === undefined,
+                       'Destroyed listview.'
+               );
+       } );
+
        function assertOnMaybePromise( assert, maybePromise, expectedVal ) {
                if( maybePromise.done ) {
                        maybePromise.done( function( val ) {
diff --git 
a/lib/tests/qunit/jquery.wikibase/jquery.wikibase.entityview.tests.js 
b/lib/tests/qunit/jquery.wikibase/jquery.wikibase.entityview.tests.js
index a8227da..b6c7d2b 100644
--- a/lib/tests/qunit/jquery.wikibase/jquery.wikibase.entityview.tests.js
+++ b/lib/tests/qunit/jquery.wikibase/jquery.wikibase.entityview.tests.js
@@ -21,10 +21,7 @@
                },
                api: 'i am an Api',
                valueViewBuilder: 'i am a valueview builder',
-               value: new wb.datamodel.Item( {
-                       id: 'Q1',
-                       type: 'item'
-               } ) // FIXME: value is optional according to doc
+               value: new wb.datamodel.Item( 'Q1' ) // FIXME: value is 
optional according to doc
        }, options || {} );
 
        $node = $node || $( '<div/>' ).appendTo( 'body' );
@@ -81,6 +78,14 @@
                $entityview.data( 'entityview' ) === undefined,
                'Destroyed widget.'
        );
+
+       $entityview = createEntityview( { languages: [ 'ku' ] } );
+       entityview = $entityview.data( 'entityview' );
+
+       assert.ok(
+               entityview instanceof $.wikibase.entityview,
+               'Created widget with a language.'
+       );
 } );
 
 }( jQuery, wikibase, QUnit ) );
diff --git 
a/lib/tests/qunit/jquery.wikibase/jquery.wikibase.referenceview.tests.js 
b/lib/tests/qunit/jquery.wikibase/jquery.wikibase.referenceview.tests.js
index 6431557..ff10e88 100644
--- a/lib/tests/qunit/jquery.wikibase/jquery.wikibase.referenceview.tests.js
+++ b/lib/tests/qunit/jquery.wikibase/jquery.wikibase.referenceview.tests.js
@@ -11,12 +11,13 @@
                get: function() {
                        return $.Deferred().resolve( new 
wb.store.FetchedContent( {
                                title: new mw.Title( 'Property:P1' ),
-                               content: new wb.datamodel.Property( {
-                                       id: 'P1',
-                                       type: 'property',
-                                       datatype: 'string',
-                                       label: { en: 'P1' }
-                               } )
+                               content: new wb.datamodel.Property(
+                                       'P1',
+                                       'string',
+                                       new wb.datamodel.Fingerprint( new 
wb.datamodel.TermMap( [
+                                               new wb.datamodel.Term( 'en', 
'P1' )
+                                       ] ) )
+                               )
                        } ) );
                }
        };
@@ -111,9 +112,9 @@
 
        QUnit.test( 'is initialized with a value', function( assert ) {
                var $node = createReferenceview( 'testGuid', {
-                               value: new wb.datamodel.Reference(
+                               value: new wb.datamodel.Reference( new 
wb.datamodel.SnakList( [
                                        new wb.datamodel.PropertyNoValueSnak( 
'P1' )
-                               )
+                               ] ) )
                        } ),
                        referenceview = $node.data( 'referenceview' );
 
diff --git 
a/lib/tests/qunit/jquery.wikibase/jquery.wikibase.snaklistview.tests.js 
b/lib/tests/qunit/jquery.wikibase/jquery.wikibase.snaklistview.tests.js
index 1d3b2a6..704e421 100644
--- a/lib/tests/qunit/jquery.wikibase/jquery.wikibase.snaklistview.tests.js
+++ b/lib/tests/qunit/jquery.wikibase/jquery.wikibase.snaklistview.tests.js
@@ -31,35 +31,19 @@
        var entities = {
                p1: new wb.store.FetchedContent( {
                        title: new mw.Title( 'Property:P1' ),
-                       content: new wb.datamodel.Property( {
-                               id: 'P1',
-                               type: 'property',
-                               datatype: 'string'
-                       } )
+                       content: new wb.datamodel.Property( 'P1', 'string' )
                } ),
                p2: new wb.store.FetchedContent( {
                        title: new mw.Title( 'Property:P2' ),
-                       content: new wb.datamodel.Property( {
-                               id: 'P2',
-                               type: 'property',
-                               datatype: 'string'
-                       } )
+                       content: new wb.datamodel.Property( 'P2', 'string' )
                } ),
                p3: new wb.store.FetchedContent( {
                        title: new mw.Title( 'Property:P3' ),
-                       content: new wb.datamodel.Property( {
-                               id: 'P3',
-                               type: 'property',
-                               datatype: 'string'
-                       } )
+                       content: new wb.datamodel.Property( 'P3', 'string' )
                } ),
                p4: new wb.store.FetchedContent( {
                        title: new mw.Title( 'Property:P4' ),
-                       content: new wb.datamodel.Property( {
-                               id: 'P4',
-                               type: 'property',
-                               datatype: 'string'
-                       } )
+                       content: new wb.datamodel.Property( 'P4', 'string' )
                } )
        };
 
@@ -354,7 +338,7 @@
                );
 
                snaklistview = setValueKeepingInitial(
-                       snaklistview, wb.datamodel.SnakList.newFromJSON( 
snakLists[0].toJSON() )
+                       snaklistview, new wb.datamodel.SnakList( 
snakLists[0].toArray() )
                );
 
                assert.ok(
diff --git a/lib/tests/qunit/jquery.wikibase/resources.php 
b/lib/tests/qunit/jquery.wikibase/resources.php
index c9b7c1d..ef6c107 100644
--- a/lib/tests/qunit/jquery.wikibase/resources.php
+++ b/lib/tests/qunit/jquery.wikibase/resources.php
@@ -48,6 +48,16 @@
                        ),
                ),
 
+               'jquery.wikibase.claimgrouplistview.tests' => $moduleBase + 
array(
+                       'scripts' => array(
+                               'jquery.wikibase.claimgrouplistview.tests.js',
+                       ),
+                       'dependencies' => array(
+                               'jquery.wikibase.claimgrouplistview',
+                               'wikibase.datamodel'
+                       ),
+               ),
+
                'jquery.wikibase.claimview.tests' => $moduleBase + array(
                        'scripts' => array(
                                'jquery.wikibase.claimview.tests.js',
diff --git a/lib/tests/qunit/wikibase.store/store.MwConfigEntityStore.tests.js 
b/lib/tests/qunit/wikibase.store/store.MwConfigEntityStore.tests.js
index 321b3e3..8624849 100644
--- a/lib/tests/qunit/wikibase.store/store.MwConfigEntityStore.tests.js
+++ b/lib/tests/qunit/wikibase.store/store.MwConfigEntityStore.tests.js
@@ -25,7 +25,7 @@
                );
 
                var store = new wb.store.MwConfigEntityStore( {
-                       unserialize: function( data ) {
+                       deserialize: function( data ) {
                                return data;
                        }
                } );
diff --git a/repo/resources/Resources.php b/repo/resources/Resources.php
index a984f4f..d93cba0 100644
--- a/repo/resources/Resources.php
+++ b/repo/resources/Resources.php
@@ -46,7 +46,7 @@
                                'wikibase.parsers.getStore',
                                'wikibase.RepoApi',
                                'wikibase.RevisionStore',
-                               'wikibase.serialization.entities',
+                               'wikibase.serialization.EntityDeserializer',
                                'wikibase.sites',
                                'wikibase.store.ApiEntityStore',
                                'wikibase.store.CombiningEntityStore',
@@ -73,13 +73,8 @@
                        'dependencies' => array(
                                'json',
                                'wikibase',
-                               'wikibase.datamodel',
-                               'wikibase.serialization',
-                               // FIXME: Resolve implicitly required 
wikibase.serialization.entities dependency.
-                               // wikibase.serialization.entities 
self-registers to the SerializerFactory provided
-                               // by wikibase.serialization which is why 
wikibase.serialization.entities is
-                               // implicitly required as dependency.
-                               'wikibase.serialization.entities',
+                               'wikibase.datamodel.Entity',
+                               'wikibase.serialization.EntityDeserializer',
                        ),
                ),
 
diff --git a/repo/resources/wikibase.EntityInitializer.js 
b/repo/resources/wikibase.EntityInitializer.js
index 24b4bac..ae7abb5 100644
--- a/repo/resources/wikibase.EntityInitializer.js
+++ b/repo/resources/wikibase.EntityInitializer.js
@@ -9,7 +9,7 @@
 
        /**
         * Entity initializer.
-        * Unserializes the entity passed to JavaScript via mw.config variable.
+        * Deserializes the entity passed to JavaScript via mw.config variable.
         * @constructor
         * @since 0.5
         *
@@ -81,12 +81,9 @@
                                }
 
                                var entityJSON = JSON.parse( serializedEntity ),
-                                       unserializerFactory = new 
wb.serialization.SerializerFactory(),
-                                       entityUnserializer = 
unserializerFactory.newUnserializerFor(
-                                               wb.datamodel.Entity
-                                       );
+                                       entityDeserializer = new 
wb.serialization.EntityDeserializer();
 
-                               deferred.resolve( 
entityUnserializer.unserialize( entityJSON ) );
+                               deferred.resolve( 
entityDeserializer.deserialize( entityJSON ) );
                                entityJSON = null;
                        } );
 
diff --git a/repo/resources/wikibase.ui.entityViewInit.js 
b/repo/resources/wikibase.ui.entityViewInit.js
index 4732d05..89aa5d2 100644
--- a/repo/resources/wikibase.ui.entityViewInit.js
+++ b/repo/resources/wikibase.ui.entityViewInit.js
@@ -89,16 +89,16 @@
         * @return {wikibase.store.CombiningEntityStore}
         */
        function buildEntityStore( repoApi ) {
-               // Unserializer for fetched content whose content is a 
wb.datamodel.Entity:
-               var fetchedEntityUnserializer = new 
wb.store.FetchedContentUnserializer( {
-                               contentUnserializer: new 
wb.serialization.EntityUnserializer()
-                       } );
+               // Deserializer for fetched content whose content is a 
wb.datamodel.Entity:
+               var fetchedEntityDeserializer = new 
wb.store.FetchedContentUnserializer(
+                               new wb.serialization.EntityDeserializer()
+                       );
 
                return new wb.store.CombiningEntityStore( [
-                       new wb.store.MwConfigEntityStore( 
fetchedEntityUnserializer ),
+                       new wb.store.MwConfigEntityStore( 
fetchedEntityDeserializer ),
                        new wb.store.ApiEntityStore(
                                repoApi,
-                               fetchedEntityUnserializer,
+                               fetchedEntityDeserializer,
                                [ mw.config.get( 'wgUserLanguage' ) ]
                        )
                ] );

-- 
To view, visit https://gerrit.wikimedia.org/r/167206
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Iafc2ed96df9f4a36b87ea9217eddc653fd3c4b9c
Gerrit-PatchSet: 20
Gerrit-Project: mediawiki/extensions/Wikibase
Gerrit-Branch: master
Gerrit-Owner: Adrian Lang <adrian.l...@wikimedia.de>
Gerrit-Reviewer: Adrian Lang <adrian.l...@wikimedia.de>
Gerrit-Reviewer: Henning Snater <henning.sna...@wikimedia.de>
Gerrit-Reviewer: Thiemo Mättig (WMDE) <thiemo.maet...@wikimedia.de>
Gerrit-Reviewer: Tobias Gritschacher <tobias.gritschac...@wikimedia.de>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to