Daniel Werner has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/67394


Change subject: (bug 38201) Introduction of "allowedSites" option in 
SiteLinksEditTool
......................................................................

(bug 38201) Introduction of "allowedSites" option in SiteLinksEditTool

* "allowedSites" allows to set a set of sites the edit tool should allow for 
creating site links
* introduces SiteLinksEditTool.getUnusedAllowedSiteIds()
* adds some missing SiteLinksEditTool tests and does some cleanup there as well
* using the new feature, providing all SiteLinksEditTool instances with the 
right set of site links
  (depending on the group) in wikibase.ui.entityViewInit.js

Change-Id: I6524c4f1c97b072e08cec05c67e8b7e4b3b4b06d
---
M lib/resources/jquery.wikibase/jquery.wikibase.siteselector.js
M lib/resources/wikibase.ui.PropertyEditTool.EditableSiteLink.js
M lib/resources/wikibase.ui.PropertyEditTool.EditableValue.SiteIdInterface.js
M lib/resources/wikibase.ui.SiteLinksEditTool.js
M lib/tests/qunit/wikibase.ui.SiteLinksEditTool.tests.js
M repo/resources/wikibase.ui.entityViewInit.js
6 files changed, 215 insertions(+), 67 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Wikibase 
refs/changes/94/67394/1

diff --git a/lib/resources/jquery.wikibase/jquery.wikibase.siteselector.js 
b/lib/resources/jquery.wikibase/jquery.wikibase.siteselector.js
index 119aff8..8bb7e32 100644
--- a/lib/resources/jquery.wikibase/jquery.wikibase.siteselector.js
+++ b/lib/resources/jquery.wikibase/jquery.wikibase.siteselector.js
@@ -19,7 +19,7 @@
         * @example $( 'input' ).siteselector( { resultSet: < list of wikibase 
Site objects > } );
         * @desc Creates a simple site selector.
         *
-        * @option resultSet {wb.Site[]} Set of sites that shall be filtered 
for any result(s).
+        * @option resultSet {wb.Site[]} Set of sites that should be available 
as selectable options.
         */
        $.widget( 'wikibase.siteselector', $.ui.suggester, {
                /**
diff --git a/lib/resources/wikibase.ui.PropertyEditTool.EditableSiteLink.js 
b/lib/resources/wikibase.ui.PropertyEditTool.EditableSiteLink.js
index d470b41..ee70ac3 100644
--- a/lib/resources/wikibase.ui.PropertyEditTool.EditableSiteLink.js
+++ b/lib/resources/wikibase.ui.PropertyEditTool.EditableSiteLink.js
@@ -258,7 +258,7 @@
        preserveEmptyForm: false,
 
        /**
-        * Allows to specify an array with sites which should not be allowed to 
choose
+        * Allows to specify an array with sites which should not be allowed to 
be chosen
         * @var wikibase.Site[]
         */
        ignoredSiteLinks: null
diff --git 
a/lib/resources/wikibase.ui.PropertyEditTool.EditableValue.SiteIdInterface.js 
b/lib/resources/wikibase.ui.PropertyEditTool.EditableValue.SiteIdInterface.js
index 220d825..4edcb73 100644
--- 
a/lib/resources/wikibase.ui.PropertyEditTool.EditableValue.SiteIdInterface.js
+++ 
b/lib/resources/wikibase.ui.PropertyEditTool.EditableValue.SiteIdInterface.js
@@ -109,7 +109,7 @@
                        }
                }
 
-               // find out which site ids should be selectable and add them as 
auto selct choice
+               // find out which site ids should be selectable and add them as 
auto select choice
                this._currentResults = [];
                for ( var siteId in wb.getSites() ) {
                        if( $.inArray( siteId, ignoredSites ) === -1 ) {
diff --git a/lib/resources/wikibase.ui.SiteLinksEditTool.js 
b/lib/resources/wikibase.ui.SiteLinksEditTool.js
index d6ba1bc..0d86b37 100644
--- a/lib/resources/wikibase.ui.SiteLinksEditTool.js
+++ b/lib/resources/wikibase.ui.SiteLinksEditTool.js
@@ -41,7 +41,7 @@
                var self = this;
 
                // setting default options
-               options = $.extend( {}, PARENT.prototype._options, {
+               this._options = $.extend( {}, PARENT.prototype._options, {
                        /**
                         * @see 
wikibase.ui.PropertyEditTool.allowsMultipleValues
                         */
@@ -50,10 +50,29 @@
                        /**
                         * @see wikibase.ui.PropertyEditTool.fullListMessage
                         */
-                       fullListMessage: mw.msg( 
'wikibase-sitelinksedittool-full' )
+                       fullListMessage: mw.msg( 
'wikibase-sitelinksedittool-full' ),
+
+                       /**
+                        * Should contain all the sites that can be used in 
creating site links
+                        * @type wb.Site[]|Object
+                        */
+                       allowedSites: []
                } );
 
                PARENT.prototype._init.call( this, subject, options );
+
+               // TODO: Just introduce a SiteList prototype which will make 
all of the (even incomplete)
+               //  validation here pointless, allowing to get rid of some 
complexity here.
+               var allowedSites = this.getOption( 'allowedSites' );
+
+               if( !$.isArray( allowedSites ) && !$.isPlainObject( 
allowedSites ) ) {
+                       throw new Error( '"allowedSites" option has to be an 
array or plain object' );
+               }
+               $.each( allowedSites, function( i, site ) {
+                       if( !( site instanceof wb.Site ) ) {
+                               throw new Error( '"allowedSites" option has to 
be a set of wb.Site objects' );
+                       }
+               } );
 
                this._fixateTableLayout();
 
@@ -66,7 +85,6 @@
                        // initially sort on the site id column
                        this._subject.tablesorter( { sortList: [{1:'asc'}] } );
                }
-
        },
 
        /**
@@ -95,9 +113,6 @@
         */
        _initEditToolForValues: function() {
                PARENT.prototype._initEditToolForValues.call( this );
-
-               // make sure selecting a language in EditableSiteLink only 
offers languages not yet chosen
-               this.getEditableValuePrototype().prototype.ignoredSiteLinks = 
this.getRepresentedSiteIds();
        },
 
        /**
@@ -179,26 +194,7 @@
         * @return {Boolean}
         */
        isFull: function() {
-               var allSites = wb.getSites(),
-                       usedSiteIds = this.getRepresentedSiteIds();
-
-               // Check each site if it is represented since there may be 
invalid sites in the DB.
-               var isFull = true;
-               $.each( allSites, function( siteId, site ) {
-                       var found = false;
-                       $.each( usedSiteIds, function( i, usedSiteId ) {
-                               if ( usedSiteId === site.getId() ) {
-                                       found = true;
-                                       return false; // break
-                               }
-                       } );
-                       if ( !found ) {
-                               isFull = false;
-                               return false; // break
-                       }
-               } );
-
-               return isFull;
+               return this.getUnusedAllowedSiteIds().length === 0;
        },
 
        /**
@@ -245,7 +241,23 @@
                        EnhancedProto = function() { BaseProto.apply( this, 
arguments ); };
 
                EnhancedProto.prototype = new BaseProto();
-               EnhancedProto.prototype.ignoredSiteLinks = 
this.getRepresentedSiteIds();
+
+               // Make sure selecting a language in EditableSiteLink only 
offers sites not yet chosen
+               // and sites this edit tool is actually responsible for (e.g. 
because they are in a certain
+               // group).
+               var ignoredSiteIds = [],
+                       unusedAllowedSiteIds = this.getUnusedAllowedSiteIds();
+
+               // TODO: very ugly to access global set of all sites here. Also 
kind of ugly to do this by
+               //  abusing the prototype field of the EditableValue instances 
here. Instead, the
+               //  "ignoredSiteLinks" thing (which is even named wrong) should 
go away, instead we should
+               //  have "allowedSites" options all the way to the 
SiteIdInterface.
+               $.each( wb.getSites(), function( siteId, site ) {
+                       if( $.inArray( siteId, unusedAllowedSiteIds ) === -1 ) {
+                               ignoredSiteIds.push( siteId );
+                       }
+               } );
+               EnhancedProto.prototype.ignoredSiteLinks = ignoredSiteIds;
 
                // don't forget to forward factory function
                EnhancedProto.newFromDom = function( subject, options, toolbar 
) {
@@ -392,9 +404,9 @@
        },
 
        /**
-        * Returns a list of sites already represented with a value.
+        * Returns a list of site IDs already used in a site link of this 
SiteLinkEditTool.
         *
-        * @return {String[]} Array of site ids
+        * @return {String[]} Array of site IDs
         */
        getRepresentedSiteIds: function() {
                var sites = [];
@@ -410,6 +422,29 @@
        },
 
        /**
+        * Returns a list of site IDs which can be used but have not yet been 
used in a site link of
+        * this SiteLinkEditTool.
+        *
+        * @since 0.4
+        *
+        * @return {String[]} Array of site IDs
+        */
+       getUnusedAllowedSiteIds: function() {
+               var allowedSites = this.getOption( 'allowedSites' ), // can be 
object or array
+                       representedSiteIds = this.getRepresentedSiteIds(),
+                       unusedAllowedSiteIds = [];
+
+               for( var i in allowedSites ) {
+                       var allowedSiteId = allowedSites[i].getId();
+
+                       if( $.inArray( allowedSiteId, representedSiteIds ) === 
-1 ) {
+                               unusedAllowedSiteIds.push( allowedSiteId );
+                       }
+               }
+               return unusedAllowedSiteIds;
+       },
+
+       /**
         * @see wb.ui.PropertyEditTool._getCounterNodes
         *
         * @return jQuery
diff --git a/lib/tests/qunit/wikibase.ui.SiteLinksEditTool.tests.js 
b/lib/tests/qunit/wikibase.ui.SiteLinksEditTool.tests.js
index 153c924..be4f2a3 100644
--- a/lib/tests/qunit/wikibase.ui.SiteLinksEditTool.tests.js
+++ b/lib/tests/qunit/wikibase.ui.SiteLinksEditTool.tests.js
@@ -7,10 +7,10 @@
  * @ingroup WikibaseLib
  *
  * @licence GNU GPL v2+
- * @author Daniel Werner
+ * @author Daniel Werner < [email protected] >
  */
 
-( function( mw, wb, $, QUnit, undefined ) {
+( function( mw, wb, $, QUnit ) {
        'use strict';
 
        var config = {
@@ -22,7 +22,7 @@
                                pageUrl: 'http://en.wikipedia.org/wiki/$1',
                                shortName: 'English',
                                languageCode: 'en',
-                               globalSiteIt: 'enwiki'
+                               globalSiteId: 'enwiki'
                        },
                        de: {
                                apiUrl: 'http://de.wikipedia.org/w/api.php',
@@ -39,20 +39,144 @@
        QUnit.module( 'wikibase.ui.SiteLinksEditTool', QUnit.newWbEnvironment( {
                config: config,
                setup: function() {
-
-                       this.apiResponse = {
-                               entity: { sitelinks: { dewiki: { title: 
'ein_titel' } } }
-                       };
-
                        // get empty nodes we get when no links on the site yet:
-                       var dom = wb.ui.SiteLinksEditTool.getEmptyStructure();
+                       var $dom = wb.ui.SiteLinksEditTool.getEmptyStructure();
 
                        // initialize:
-                       this.subject = new wb.ui.SiteLinksEditTool( dom );
+                       this.subject = new wb.ui.SiteLinksEditTool( $dom, {
+                               allowedSites: wb.getSites() // TODO: decouple 
test from abusing global config here
+                       } );
                },
-               teardown: function() {}
+               teardown: function() {
+                       this.subject.destroy();
+               }
        } ) );
 
+       /**
+        * Allows to enter a value into the SiteLinksEditTool which can then be 
saved by calling
+        * stopEditing( true ) on the returned EditableValue. This is necessary 
because of some ugly
+        * fake API requests have to be mocked to do this.
+        *
+        * @param editTool
+        * @param siteLink
+        * @param siteLinkGlobalId
+        * @returns {wb.ui.PropertyEditTool.EditableValue}
+        */
+       function hackyValueInsertion( editTool, siteLink, siteLinkGlobalId ) {
+               var initialValue = siteLink,
+                       newValue = editTool.enterNewValue( initialValue );
+
+               // override AJAX API call
+               newValue.triggerApi = function( deferred, apiAction ) {
+                       deferred.resolve( {} );
+               };
+
+               // set result set for validation
+               newValue.sitePageInterface.setResultSet( siteLink[1] );
+
+               // pretend API success
+               var fakeApiResponse = { entity: { sitelinks: {} } };
+               fakeApiResponse.entity.sitelinks[ siteLinkGlobalId ] = { title: 
'whatever_title' };
+
+               newValue.triggerApi = function( deferred, apiAction ) {
+                       deferred.resolve( fakeApiResponse );
+               };
+               return newValue;
+       }
+
+       /**
+        * Just like hackyValueInsertion but does the stopEditing as well.
+        *
+        * @see hackyValueInsertion
+        */
+       function hackyValueInsertionAndSave( editTool, siteLink, 
siteLinkGlobalId ) {
+               var newValue = hackyValueInsertion.apply( null, arguments );
+
+               // TODO: stopEditing() should not fail for the 2nd value when 
not doing this
+               var realTablesorter = $.fn.tablesorter;
+               $.fn.tablesorter = $.noop;
+
+               newValue.stopEditing( true );
+
+               $.fn.tablesorter = realTablesorter;
+
+               return newValue;
+       }
+
+       QUnit.test( 'getUnusedAllowedSiteIds()', function( assert ) {
+               var subject = this.subject;
+
+               assert.deepEqual(
+                       subject.getUnusedAllowedSiteIds(),
+                       [ 'en', 'de' ],
+                       'all allowed site links are returned as unused by newly 
initialized edit tool'
+               );
+
+               hackyValueInsertionAndSave( subject, [ 'en', 'London' ], 
'enwiki' );
+
+               assert.deepEqual(
+                       subject.getUnusedAllowedSiteIds(),
+                       [ 'de' ],
+                       'after site has been used, the site will not be 
returned anymore'
+               );
+
+               hackyValueInsertionAndSave( subject, [ 'de', 'Berlin' ], 
'dewiki' );
+
+               assert.deepEqual(
+                       subject.getUnusedAllowedSiteIds(),
+                       [],
+                       'after all sites are used, an empty array will be 
returned'
+               );
+       } );
+
+       QUnit.test( 'getUnusedAllowedSiteIds()', function( assert ) {
+               var subject = this.subject;
+
+               assert.deepEqual(
+                       subject.getRepresentedSiteIds(),
+                       [],
+                       'initially, no site links, so no sites represented yet'
+               );
+
+               hackyValueInsertionAndSave( subject, [ 'en', 'London' ], 
'enwiki' );
+
+               assert.deepEqual(
+                       subject.getRepresentedSiteIds(),
+                       [ 'en' ],
+                       'after site has been used, the site will be returned'
+               );
+
+               hackyValueInsertionAndSave( subject, [ 'de', 'Berlin' ], 
'dewiki' );
+
+               assert.deepEqual(
+                       subject.getRepresentedSiteIds(),
+                       [ 'en', 'de' ],
+                       'after another site link has been entered, both sites 
will be returned'
+               );
+       } );
+
+       QUnit.test( 'isFull()', function( assert ) {
+               var subject = this.subject;
+
+               assert.ok(
+                       !subject.isFull(),
+                       'not full initially'
+               );
+
+               hackyValueInsertionAndSave( subject, [ 'de', 'Berlin' ], 
'dewiki' );
+
+               assert.ok(
+                       !subject.isFull(),
+                       'not full after entering one site link'
+               );
+
+               hackyValueInsertionAndSave( subject, [ 'en', 'London' ], 
'enwiki' );
+
+               assert.ok(
+                       subject.isFull(),
+                       'full after entering site links for all available sites'
+               );
+       } );
 
        QUnit.test( 'adding a new editable site link', function( assert ) {
 
@@ -61,29 +185,16 @@
                        'editable values initiated correctly'
                );
 
-               var initialValue = [ 'Deutsch (de)', 'Berlin' ];
-               var newValue = this.subject.enterNewValue( initialValue );
+               var rawNewValue = [ 'Deutsch (de)', 'Berlin' ];
+               var newValue = hackyValueInsertion( this.subject, rawNewValue, 
'dewiki' );
 
-               // override AJAX API call
-               this.subject._editableValues[0].triggerApi = function( 
deferred, apiAction ) {
-                       deferred.resolve( {} );
-               };
-
-               // set result set for validation
-               this.subject._editableValues[0].sitePageInterface.setResultSet( 
['Berlin'] );
-
-               // pretend API success
-               newValue.triggerApi = $.proxy( function( deferred, apiAction ) {
-                       deferred.resolve( this.apiResponse );
-               }, this );
-
-               assert.equal(
+               assert.strictEqual(
                        this.subject.getValues().length,
                        0,
                        'getValues() should return no elements since the new 
one is still pending'
                );
 
-               assert.equal(
+               assert.strictEqual(
                        this.subject.getValues( true ).length,
                        1,
                        'getValues( true ) should return the pending element'
@@ -108,27 +219,27 @@
                        'new value has the value set in enterNewValue( value )'
                );
 
-               assert.equal(
+               assert.strictEqual(
                        newValue.startEditing(),
                        false,
                        'start editing already active, call function again'
                );
 
-               assert.equal(
+               assert.strictEqual(
                        newValue.stopEditing( true ).promisor.apiAction,
                        newValue.API_ACTION.SAVE,
                        'stopped editing (save), true returned because value 
has changed (it was created)'
                );
 
-               assert.equal(
-                       
this.subject.enterNewValue().siteIdInterface.getResultSetMatch( initialValue[0] 
),
+               assert.strictEqual(
+                       
this.subject.enterNewValue().siteIdInterface.getResultSetMatch( rawNewValue ),
                        null,
-                       'The site id set already shouldn\'t be available in the 
set of suggestions anymore'
+                       'The site id set already should not be available in the 
set of suggestions anymore'
                );
 
                this.subject.destroy();
 
-               assert.equal(
+               assert.strictEqual(
                        this.subject._editableValues,
                        null,
                        'destroyed editable values'
diff --git a/repo/resources/wikibase.ui.entityViewInit.js 
b/repo/resources/wikibase.ui.entityViewInit.js
index 53be11a..83be1d8 100644
--- a/repo/resources/wikibase.ui.entityViewInit.js
+++ b/repo/resources/wikibase.ui.entityViewInit.js
@@ -141,7 +141,9 @@
                                        )
                                );
                                // actual initialization
-                               new wb.ui.SiteLinksEditTool( $( this ) );
+                               new wb.ui.SiteLinksEditTool( $( this ), {
+                                       allowedSites: wb.getSitesOfGroup( group 
)
+                               } );
                        } );
 
                        // BUILD TOOLBARS

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: I6524c4f1c97b072e08cec05c67e8b7e4b3b4b06d
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/Wikibase
Gerrit-Branch: master
Gerrit-Owner: Daniel Werner <[email protected]>

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

Reply via email to