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

Change subject: Use ViewFactory for building snakviews in snaklistview
......................................................................


Use ViewFactory for building snakviews in snaklistview

This change introduces a `ViewFactory` method for building `ListItemAdapter`s
for `snakview` widgets. This `ListItemAdapter` is passed to the `snaklistview`
so that it can create the widgets without having to pass them all their
dependencies.

This change leaves `listview` as an implementation detail of `snaklistview`.
This implementation detail is publicly represented by having to pass in a
`listview.ListItemAdapter`.

It improves separation between the `snaklistview` and `snakview`, since the
`snaklistview` doesn't have to know how to construct a `snakview` anymore. It
also allows to inject a different implementation, for example in tests.

`snakview::propertyLabelIsVisible` is removed, since it was only used in the
`snaklistview` tests. I also removed a duplicate `change` event binding.

Bug: T75380

Change-Id: I3f89b733139d7ced99b9044305298b723f4e9e80
---
M view/resources/jquery/wikibase/jquery.wikibase.snaklistview.js
M view/resources/jquery/wikibase/resources.php
M view/resources/jquery/wikibase/snakview/snakview.js
M view/resources/wikibase/view/ViewFactory.js
M view/tests/qunit/jquery/wikibase/jquery.wikibase.snaklistview.tests.js
M view/tests/qunit/jquery/wikibase/resources.php
M view/tests/qunit/wikibase/view/ViewFactory.tests.js
7 files changed, 126 insertions(+), 131 deletions(-)

Approvals:
  Jonas Kress (WMDE): Looks good to me, approved
  jenkins-bot: Verified



diff --git a/view/resources/jquery/wikibase/jquery.wikibase.snaklistview.js 
b/view/resources/jquery/wikibase/jquery.wikibase.snaklistview.js
index 013c893..762487b 100644
--- a/view/resources/jquery/wikibase/jquery.wikibase.snaklistview.js
+++ b/view/resources/jquery/wikibase/jquery.wikibase.snaklistview.js
@@ -19,21 +19,10 @@
  * @param {Object} options
  * @param {wikibase.datamodel.SnakList} [value=new 
wikibase.datamodel.SnakList()]
  *        The `SnakList` to be displayed by this view.
+ * @param {jQuery.wikibase.listview.ListItemAdapter} options.listItemAdapter
  * @param {boolean} [singleProperty=true]
  *        If `true`, it is assumed that the widget is filled with `Snak`s 
featuring a single common
  *        property.
- * @param {wikibase.entityIdFormatter.EntityIdHtmlFormatter} 
options.entityIdHtmlFormatter
- *        Required for dynamically rendering links to `Entity`s.
- * @param {wikibase.entityIdFormatter.EntityIdPlainFormatter} 
options.entityIdPlainFormatter
- *        Required for dynamically rendering plain text references to 
`Entity`s.
- * @param {wikibase.store.EntityStore} options.entityStore
- *        Required for dynamically gathering `Entity`/`Property` information.
- * @param {wikibase.ValueViewBuilder} options.valueViewBuilder
- *        Required by the `snakview` interfacing a `snakview` "value" 
`Variation` to
- *        `jQuery.valueview`.
- * @param {dataTypes.DataTypeStore} options.dataTypeStore
- *        Required by the `snakview` for retrieving and evaluating a proper 
`dataTypes.DataType`
- *        object when interacting on a "value" `Variation`.
  * @param {string} [optionshelpMessage=mw.msg( 
'wikibase-claimview-snak-new-tooltip' )]
  *        End-user message explaining how to use the `snaklistview` widget. 
The message is most
  *        likely to be used inside the tooltip of the toolbar corresponding to 
the `snaklistview`.
@@ -77,12 +66,8 @@
                },
                value: null,
                singleProperty: false,
-               helpMessage: mw.msg( 'wikibase-claimview-snak-new-tooltip' ),
-               entityIdHtmlFormatter: null,
-               entityIdPlainFormatter: null,
-               entityStore: null,
-               valueViewBuilder: null,
-               dataTypeStore: null
+               listItemAdapter: null,
+               helpMessage: mw.msg( 'wikibase-claimview-snak-new-tooltip' )
        },
 
        /**
@@ -116,11 +101,7 @@
        _create: function() {
                this.options.value = this.options.value || new 
wb.datamodel.SnakList();
 
-               if ( !this.options.entityStore
-                       || !this.options.valueViewBuilder
-                       || !this.options.dataTypeStore
-                       || !( this.options.value instanceof 
wb.datamodel.SnakList )
-               ) {
+               if ( !this.options.listItemAdapter || !( this.options.value 
instanceof wb.datamodel.SnakList ) ) {
                        throw new Error( 'Required option not specified 
properly' );
                }
 
@@ -152,26 +133,7 @@
                }
 
                this.$listview.listview( {
-                       listItemAdapter: new 
$.wikibase.listview.ListItemAdapter( {
-                               listItemWidget: $.wikibase.snakview,
-                               newItemOptionsFn: function( value ) {
-                                       return {
-                                               value: value || {
-                                                       property: null,
-                                                       snaktype: 
wb.datamodel.PropertyValueSnak.TYPE
-                                               },
-                                               locked: {
-                                                       // Do not allow 
changing the property when editing existing an snak.
-                                                       property: !!value
-                                               },
-                                               dataTypeStore: self.option( 
'dataTypeStore' ),
-                                               entityIdHtmlFormatter: 
self.options.entityIdHtmlFormatter,
-                                               entityIdPlainFormatter: 
self.options.entityIdPlainFormatter,
-                                               entityStore: self.option( 
'entityStore' ),
-                                               valueViewBuilder: self.option( 
'valueViewBuilder' )
-                                       };
-                               }
-                       } ),
+                       listItemAdapter: this.options.listItemAdapter,
                        value: this.options.value.toArray()
                } );
 
@@ -185,14 +147,6 @@
 
                this.$listview
                .off( '.' + this.widgetName )
-               .on( 'listviewitemadded.' + this.widgetName, function( event, 
value, $newLi ) {
-                       // Listen to all the snakview "change" events to be 
able to determine whether the
-                       // snaklistview itself is valid.
-                       $newLi.on( self._lia.prefixedEvent( 'change' ), 
function( event ) {
-                               // Forward the "change" event to external 
components (e.g. the edit toolbar).
-                               self._trigger( 'change' );
-                       } );
-               } )
                .on( this._lia.prefixedEvent( 'change.' ) + this.widgetName
                        + ' listviewafteritemmove.' + this.widgetName
                        + ' listviewitemremoved.' + this.widgetName, function( 
event ) {
diff --git a/view/resources/jquery/wikibase/resources.php 
b/view/resources/jquery/wikibase/resources.php
index dbe4fc4..a52543f 100644
--- a/view/resources/jquery/wikibase/resources.php
+++ b/view/resources/jquery/wikibase/resources.php
@@ -392,10 +392,9 @@
                        ),
                        'dependencies' => array(
                                'jquery.ui.TemplatedWidget',
-                               'jquery.ui.widget',
                                'jquery.wikibase.listview',
-                               'jquery.wikibase.snakview',
-                               'wikibase.datamodel',
+                               'wikibase.datamodel.Snak',
+                               'wikibase.datamodel.SnakList',
                        ),
                        'messages' => array(
                                'wikibase-claimview-snak-tooltip',
diff --git a/view/resources/jquery/wikibase/snakview/snakview.js 
b/view/resources/jquery/wikibase/snakview/snakview.js
index 8865f66..4dc08b0 100644
--- a/view/resources/jquery/wikibase/snakview/snakview.js
+++ b/view/resources/jquery/wikibase/snakview/snakview.js
@@ -918,15 +918,8 @@
         */
        showPropertyLabel: function() {
                this.$property.show();
-       },
-
-       /**
-        * Returns whether the property label currently is visible.
-        * @since 0.5
-        */
-       propertyLabelIsVisible: function() {
-               return this.$property.is( ':visible' );
        }
+
 } );
 
 $.extend( $.wikibase.snakview, existingSnakview );
diff --git a/view/resources/wikibase/view/ViewFactory.js 
b/view/resources/wikibase/view/ViewFactory.js
index d69cf3c..18ddf59 100644
--- a/view/resources/wikibase/view/ViewFactory.js
+++ b/view/resources/wikibase/view/ViewFactory.js
@@ -350,12 +350,34 @@
                                return {
                                        value: value || undefined,
                                        singleProperty: true,
-                                       dataTypeStore: this._dataTypeStore,
-                                       entityIdHtmlFormatter: 
this._entityIdHtmlFormatter,
-                                       entityIdPlainFormatter: 
this._entityIdPlainFormatter,
-                                       entityStore: this._entityStore,
-                                       valueViewBuilder: 
this._getValueViewBuilder()
+                                       listItemAdapter: 
this.getListItemAdapterForSnakView()
                                };
+                       }, this )
+               } );
+       };
+
+       /**
+        * Construct a `ListItemAdapter` for `snakview`s
+        *
+        * @return {jQuery.wikibase.listview.ListItemAdapter} The constructed 
ListItemAdapter
+        */
+       SELF.prototype.getListItemAdapterForSnakView = function() {
+               return new $.wikibase.listview.ListItemAdapter( {
+                       listItemWidget: $.wikibase.snakview,
+                       newItemOptionsFn: $.proxy( function( value ) {
+                               return this._getSnakViewOptions(
+                                       null,
+                                       {
+                                               locked: {
+                                                       // Do not allow 
changing the property when editing existing an snak.
+                                                       property: Boolean( 
value )
+                                               }
+                                       },
+                                       value || {
+                                               property: null,
+                                               snaktype: 
wb.datamodel.PropertyValueSnak.TYPE
+                                       }
+                               );
                        }, this )
                } );
        };
@@ -373,21 +395,30 @@
                return this._getView(
                        'snakview',
                        $dom,
-                       {
-                               value: snak || undefined,
-                               locked: options.locked,
-                               autoStartEditing: options.autoStartEditing,
-                               dataTypeStore: this._dataTypeStore,
-                               entityIdHtmlFormatter: 
this._entityIdHtmlFormatter,
-                               entityIdPlainFormatter: 
this._entityIdPlainFormatter,
-                               entityStore: this._entityStore,
-                               valueViewBuilder: this._getValueViewBuilder(),
-                               encapsulatedBy: encapsulatedBy
-                       }
+                       this._getSnakViewOptions( encapsulatedBy, options, snak 
)
                );
        };
 
        /**
+        * @param {string|null} encapsulatedBy A jQuery selector for getting 
the encapsulating view
+        * @param {Object} options An object with keys `locked` and 
`autoStartEditing`
+        * @param {wikibase.datamodel.Snak|null} snak
+        */
+       SELF.prototype._getSnakViewOptions = function( encapsulatedBy, options, 
snak ) {
+               return {
+                       value: snak || undefined,
+                       locked: options.locked,
+                       autoStartEditing: options.autoStartEditing,
+                       dataTypeStore: this._dataTypeStore,
+                       entityIdHtmlFormatter: this._entityIdHtmlFormatter,
+                       entityIdPlainFormatter: this._entityIdPlainFormatter,
+                       entityStore: this._entityStore,
+                       valueViewBuilder: this._getValueViewBuilder(),
+                       encapsulatedBy: encapsulatedBy
+               };
+       };
+
+       /**
         * @private
         * @return {wikibase.ValueViewBuilder}
         **/
diff --git 
a/view/tests/qunit/jquery/wikibase/jquery.wikibase.snaklistview.tests.js 
b/view/tests/qunit/jquery/wikibase/jquery.wikibase.snaklistview.tests.js
index 88ba36b..8b856f1 100644
--- a/view/tests/qunit/jquery/wikibase/jquery.wikibase.snaklistview.tests.js
+++ b/view/tests/qunit/jquery/wikibase/jquery.wikibase.snaklistview.tests.js
@@ -2,7 +2,7 @@
  * @licence GNU GPL v2+
  * @author H. Snater < [email protected] >
  */
-( function( mw, $, wb, dv, vf, vv, QUnit ) {
+( function( $, wb, dv, QUnit ) {
        'use strict';
 
        var snakLists = [
@@ -26,27 +26,29 @@
                new wb.datamodel.PropertyValueSnak( 'p4',  new dv.StringValue( 
'g' ) )
        ];
 
-       // We need a filled entity store for the instances of 
jQuery.wikibase.snakview.variations.Value
-       // and jQuery.wikibase.snakview created by jQuery.wikibase.snaklistview.
-       var entities = {
-               p1: new wb.datamodel.Property( 'P1', 'string' ),
-               p2: new wb.datamodel.Property( 'P2', 'string' ),
-               p3: new wb.datamodel.Property( 'P3', 'string' ),
-               p4: new wb.datamodel.Property( 'P4', 'string' )
-       };
+       var listItemAdapter = wb.tests.getMockListItemAdapter( 'snakview', 
function() {
+               var _value = this.options.value;
+               this.options.locked = this.options.locked || {};
+               this.snak = function( value ) {
+                       if ( arguments.length ) {
+                               _value = value;
+                       }
+                       return _value;
+               };
+               this.isValid = function() {};
+               this.startEditing = function() {
+                       this._trigger( 'change' );
+                       this._trigger( 'afterstartediting' );
+               };
+               this.stopEditing = function() {};
 
-       var entityStore = {
-               get: function( entityId ) {
-                       return $.Deferred().resolve( entities[entityId] );
-               }
-       };
-
-       var valueViewBuilder = new wb.ValueViewBuilder(
-               new vv.ExpertStore(),
-               new vf.ValueFormatterStore( vf.NullFormatter ),
-               'I am a ParserStore',
-               'I am a language code'
-       );
+               this.showPropertyLabel = function() {
+                       this._propertyLabelVisible = true;
+               };
+               this.hidePropertyLabel = function() {
+                       this._propertyLabelVisible = false;
+               };
+       } );
 
        /**
         * Generates a snaklistview widget suitable for testing.
@@ -58,21 +60,7 @@
        function createSnaklistview( value, additionalOptions ) {
                var options = $.extend( additionalOptions, {
                        value: value || undefined,
-                       dataTypeStore: {
-                               getDataType: function() {}
-                       },
-                       entityIdHtmlFormatter: {
-                               format: function() {
-                                       return $.Deferred().resolve( 'P1' 
).promise();
-                               }
-                       },
-                       entityIdPlainFormatter: {
-                               format: function( entityId ) {
-                                       return $.Deferred().resolve( entityId 
).promise();
-                               }
-                       },
-                       entityStore: entityStore,
-                       valueViewBuilder: valueViewBuilder
+                       listItemAdapter: listItemAdapter
                } );
 
                return $( '<div/>' )
@@ -867,9 +855,6 @@
                var $node = createSnaklistview( snakLists[0], { singleProperty: 
true } ),
                        snaklistview = $node.data( 'snaklistview' );
 
-               // Append node to body in order to correctly detect visibility:
-               $node.appendTo( 'body' );
-
                assert.ok(
                        snaklistview._listview.items().length > 0,
                        'Initialized snaklistview with more than one item.'
@@ -882,12 +867,12 @@
 
                                if ( i === 0 ) {
                                        assert.ok(
-                                               
snakview.propertyLabelIsVisible(),
+                                               snakview._propertyLabelVisible,
                                                'Topmost snakview\'s property 
label is visible.'
                                        );
                                } else {
                                        assert.ok(
-                                               
!snakview.propertyLabelIsVisible(),
+                                               !snakview._propertyLabelVisible,
                                                'Property label of snakview 
that is not on top of the snaklistview is not '
                                                        + 'visible.'
                                        );
@@ -907,4 +892,4 @@
                testPropertyLabelVisibility( assert, snaklistview );
        } );
 
-} )( mediaWiki, jQuery, wikibase, dataValues, valueFormatters, 
jQuery.valueview, QUnit );
+} )( jQuery, wikibase, dataValues, QUnit );
diff --git a/view/tests/qunit/jquery/wikibase/resources.php 
b/view/tests/qunit/jquery/wikibase/resources.php
index a5fbf1f..faf896d 100644
--- a/view/tests/qunit/jquery/wikibase/resources.php
+++ b/view/tests/qunit/jquery/wikibase/resources.php
@@ -262,11 +262,8 @@
                        ),
                        'dependencies' => array(
                                'jquery.wikibase.snaklistview',
-                               'wikibase.ValueViewBuilder',
                                'wikibase.datamodel',
-                               'mediawiki.Title',
-                               'jquery.valueview',
-                               'valueFormatters'
+                               'wikibase.tests.getMockListItemAdapter',
                        ),
                ),
 
diff --git a/view/tests/qunit/wikibase/view/ViewFactory.tests.js 
b/view/tests/qunit/wikibase/view/ViewFactory.tests.js
index 9afd8c2..b909c9a 100644
--- a/view/tests/qunit/wikibase/view/ViewFactory.tests.js
+++ b/view/tests/qunit/wikibase/view/ViewFactory.tests.js
@@ -324,14 +324,43 @@
        } );
 
        QUnit.test( 'getListItemAdapterForSnakListView passes correct options 
to ListItemAdapter', function( assert ) {
+               var value = null,
+                       viewFactory = new ViewFactory(),
+                       ListItemAdapter = sinon.spy( $.wikibase.listview, 
'ListItemAdapter' );
+
+               viewFactory.getListItemAdapterForSnakListView();
+
+               sinon.assert.calledWith(
+                       ListItemAdapter,
+                       sinon.match( {
+                               listItemWidget: $.wikibase.snaklistview,
+                               newItemOptionsFn: sinon.match.func
+                       } )
+               );
+
+               var result = ListItemAdapter.args[0][0].newItemOptionsFn( value 
);
+
+               assert.deepEqual(
+                       result,
+                       {
+                               value: value || undefined,
+                               singleProperty: true,
+                               listItemAdapter: result.listItemAdapter // Hack
+                       }
+               );
+
+               assert.ok( result.listItemAdapter instanceof 
$.wikibase.listview.ListItemAdapter );
+
+               $.wikibase.listview.ListItemAdapter.restore();
+       } );
+
+       QUnit.test( 'getListItemAdapterForSnakView passes correct options to 
ListItemAdapter', function( assert ) {
                var contentLanguages = {},
                        value = null,
                        dataTypeStore = {},
                        claimsChanger = {},
-                       referencesChanger = {},
                        entityChangersFactory = {
-                               getClaimsChanger: function() { return 
claimsChanger; },
-                               getReferencesChanger: function() { return 
referencesChanger; }
+                               getClaimsChanger: function() { return 
claimsChanger; }
                        },
                        entityIdHtmlFormatter = {},
                        entityIdPlainFormatter = {},
@@ -356,12 +385,12 @@
                        ),
                        ListItemAdapter = sinon.spy( $.wikibase.listview, 
'ListItemAdapter' );
 
-               viewFactory.getListItemAdapterForSnakListView();
+               viewFactory.getListItemAdapterForSnakView();
 
                sinon.assert.calledWith(
                        ListItemAdapter,
                        sinon.match( {
-                               listItemWidget: $.wikibase.snaklistview,
+                               listItemWidget: $.wikibase.snakview,
                                newItemOptionsFn: sinon.match.func
                        } )
                );
@@ -373,12 +402,19 @@
                assert.deepEqual(
                        result,
                        {
-                               value: value || undefined,
-                               singleProperty: true,
+                               value: value || {
+                                       property: null,
+                                       snaktype: 'value'
+                               },
+                               autoStartEditing: undefined,
                                dataTypeStore: dataTypeStore,
+                               encapsulatedBy: null,
                                entityIdHtmlFormatter: entityIdHtmlFormatter,
                                entityIdPlainFormatter: entityIdPlainFormatter,
                                entityStore: entityStore,
+                               locked: {
+                                       property: false
+                               },
                                valueViewBuilder: 
wb.ValueViewBuilder.returnValues[0]
                        }
                );

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

Gerrit-MessageType: merged
Gerrit-Change-Id: I3f89b733139d7ced99b9044305298b723f4e9e80
Gerrit-PatchSet: 8
Gerrit-Project: mediawiki/extensions/Wikibase
Gerrit-Branch: master
Gerrit-Owner: Adrian Lang <[email protected]>
Gerrit-Reviewer: Adrian Lang <[email protected]>
Gerrit-Reviewer: Jonas Kress (WMDE) <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to