jenkins-bot has submitted this change and it was merged. ( 
https://gerrit.wikimedia.org/r/341577 )

Change subject: Add item selector to lexeme language textfield.
......................................................................


Add item selector to lexeme language textfield.

* introduces LanguageLookupWidget built on TextInputWidget and
  LookupElement using wbsearchentities
* adds classes that make it possible to createLanguageLookupWidget from PHP

Bug: T160515
Change-Id: I6ed726c3cfb223705c466548d856e13e5ab4ac37
---
M extension.json
A resources/special/NewLexeme.js
A resources/special/__namespace.js
A resources/widgets/LanguageLookupWidget.js
A resources/widgets/__namespace.js
A src/Specials/HTMLForm/LanguageLookupWidget.php
A src/Specials/HTMLForm/LanguageLookupWidgetField.php
M src/Specials/SpecialNewLexeme.php
M src/WikibaseLexeme.hooks.php
A tests/phpunit/mediawiki/Specials/HTMLForm/LanguageLookupWidgetFieldTest.php
A tests/qunit/widgets/LanguageLookupWidget.tests.js
11 files changed, 353 insertions(+), 13 deletions(-)

Approvals:
  Jonas Kress (WMDE): Looks good to me, approved
  Aleksey Bekh-Ivanov (WMDE): Looks good to me, but someone else must approve
  jenkins-bot: Verified



diff --git a/extension.json b/extension.json
index f9e7268..7de5c99 100644
--- a/extension.json
+++ b/extension.json
@@ -31,6 +31,9 @@
                ],
                "WikibaseClientEntityTypes": [
                        
"Wikibase\\Lexeme\\WikibaseLexemeHooks::onWikibaseEntityTypes"
+               ],
+               "ResourceLoaderTestModules": [
+                       
"Wikibase\\Lexeme\\WikibaseLexemeHooks::onResourceLoaderTestModules"
                ]
        },
        "MessagesDirs": {
@@ -90,6 +93,27 @@
                                "wikibase.serialization.TermMapDeserializer"
                        ]
                },
+               "wikibase.lexeme.widgets.LanguageLookupWidget": {
+                       "scripts": [
+                               "widgets/__namespace.js",
+                               "widgets/LanguageLookupWidget.js"
+                       ],
+                       "dependencies": [
+                               "oojs-ui-core",
+                               "oojs-ui-widgets",
+                               "wikibase.lexeme"
+                       ]
+               },
+               "wikibase.lexeme.special.NewLexeme": {
+                       "scripts": [
+                               "special/__namespace.js",
+                               "special/NewLexeme.js"
+                       ],
+                       "dependencies": [
+                               "mw.config.values.wbRepo",
+                               "wikibase.lexeme.widgets.LanguageLookupWidget"
+                       ]
+               },
                "wikibase.lexeme.styles": {
                        "position": "top",
                        "styles": [
diff --git a/resources/special/NewLexeme.js b/resources/special/NewLexeme.js
new file mode 100644
index 0000000..aef17db
--- /dev/null
+++ b/resources/special/NewLexeme.js
@@ -0,0 +1,20 @@
+( function ( $, mw, wb ) {
+       'use strict';
+
+       var repoConfig = mw.config.get( 'wbRepo' ),
+               repoApiUrl = repoConfig.url + repoConfig.scriptPath + 
'/api.php',
+               lookup = wb.lexeme.widgets.LanguageLookupWidget.static.infuse(
+                       'wb-newlexeme-lexeme-language'
+               );
+
+       lookup.initialize( {
+               apiUrl: repoApiUrl,
+               language: mw.config.get( 'wgUserLanguage' ),
+               timeout: 8000
+       } );
+
+}(
+       jQuery,
+       mediaWiki,
+       wikibase
+) );
diff --git a/resources/special/__namespace.js b/resources/special/__namespace.js
new file mode 100644
index 0000000..f87ea07
--- /dev/null
+++ b/resources/special/__namespace.js
@@ -0,0 +1 @@
+wikibase.lexeme.special = wikibase.lexeme.special || {};
diff --git a/resources/widgets/LanguageLookupWidget.js 
b/resources/widgets/LanguageLookupWidget.js
new file mode 100644
index 0000000..0bf062d
--- /dev/null
+++ b/resources/widgets/LanguageLookupWidget.js
@@ -0,0 +1,132 @@
+(function ( $, mw, wb ) {
+       'use strict';
+
+       /**
+        * @see OO.ui.TextInputWidget
+        *
+        * @param config
+        *
+        * @license GPL-2.0+
+        */
+       var LanguageLookupWidget = function ( config ) {
+               OO.ui.TextInputWidget.call( this, config );
+               OO.ui.mixin.LookupElement.call( this, config );
+       };
+
+       OO.inheritClass( LanguageLookupWidget, OO.ui.TextInputWidget );
+       OO.mixinClass( LanguageLookupWidget, OO.ui.mixin.LookupElement );
+
+       $.extend( LanguageLookupWidget.prototype, {
+
+               /**
+                * @property {string}
+                */
+               _language: null,
+
+               /**
+                * @property {string}
+                */
+               _apiUrl: null,
+
+               /**
+                * @property {integer}
+                */
+               _timeout: null,
+
+               /**
+                * @property {boolean}
+                */
+               _isInitialized: false,
+
+               /**
+                * Used to inject dependencies into the widget, since the 
element gets instantiated
+                * automatically from OOJS
+                *
+                * @param {Object} options containing apiUrl, language and 
timeout
+                */
+               initialize: function ( options ) {
+                       if ( !options.apiUrl || !options.language || 
!options.timeout ) {
+                               throw new Error( 'apiUrl, language and timeout 
need to be specified.' );
+                       }
+
+                       this._language = options.language;
+                       this._apiUrl = options.apiUrl;
+                       this._timeout = options.timeout;
+
+                       this._isInitialized = true;
+               },
+
+               /**
+                * @see OO.ui.mixin.LookupElement.prototype.getLookupRequest
+                */
+               getLookupRequest: function () {
+                       var term = this.getValue(),
+                               deferred = $.Deferred();
+
+                       if ( !this._isInitialized ) {
+                               throw new Error( 'The LanguageLookupWidget has 
not been properly initialized.' );
+                       }
+
+                       $.ajax( {
+                               url: this._apiUrl,
+                               timeout: this._timeout,
+                               dataType: 'json',
+                               data: this._getSearchApiParameters( term )
+                       } )
+                               .done( function ( response ) {
+                                       if ( response.error ) {
+                                               deferred.reject( 
response.error.info );
+                                               return;
+                                       }
+
+                                       deferred.resolve( response.search );
+                               } )
+                               .fail( function ( jqXHR, textStatus ) {
+                                       deferred.reject( textStatus );
+                               } );
+
+                       return deferred.promise( {
+                               abort: function () {
+                               }
+                       } );
+               },
+
+               /**
+                * @see 
OO.ui.mixin.LookupElement.prototype.getLookupCacheDataFromResponse
+                */
+               getLookupCacheDataFromResponse: function ( response ) {
+                       return response || [];
+               },
+
+               /**
+                * @see 
OO.ui.mixin.LookupElement.prototype.getLookupMenuOptionsFromData
+                */
+               getLookupMenuOptionsFromData: function ( data ) {
+                       var items = [],
+                               i;
+
+                       for ( i = 0; i < data.length; i++ ) {
+                               items.push( new OO.ui.MenuOptionWidget( {
+                                       data: data[ i ].id,
+                                       label: data[ i ].label
+                               } ) );
+                       }
+
+                       return items;
+               },
+
+               _getSearchApiParameters: function ( term ) {
+                       return {
+                               action: 'wbsearchentities',
+                               search: term,
+                               format: 'json',
+                               language: this._language,
+                               uselang: this._language,
+                               type: 'item'
+                       };
+               }
+       } );
+
+       wb.lexeme.widgets.LanguageLookupWidget = LanguageLookupWidget;
+
+})( jQuery, mediaWiki, wikibase );
diff --git a/resources/widgets/__namespace.js b/resources/widgets/__namespace.js
new file mode 100644
index 0000000..1c95fde
--- /dev/null
+++ b/resources/widgets/__namespace.js
@@ -0,0 +1 @@
+wikibase.lexeme.widgets = wikibase.lexeme.widgets || {};
diff --git a/src/Specials/HTMLForm/LanguageLookupWidget.php 
b/src/Specials/HTMLForm/LanguageLookupWidget.php
new file mode 100644
index 0000000..8971df4
--- /dev/null
+++ b/src/Specials/HTMLForm/LanguageLookupWidget.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace Wikibase\Lexeme\Specials\HTMLForm;
+
+use OOUI\TextInputWidget;
+
+/**
+ * Needed to infuse the LanguageLookupWidget into an existing form field in 
the frontend
+ *
+ * @license GPL-2.0+
+ */
+class LanguageLookupWidget extends TextInputWidget {
+
+       protected function getJavaScriptClassName() {
+               return 'wikibase.lexeme.widgets.LanguageLookupWidget';
+       }
+
+}
diff --git a/src/Specials/HTMLForm/LanguageLookupWidgetField.php 
b/src/Specials/HTMLForm/LanguageLookupWidgetField.php
new file mode 100644
index 0000000..8faaab0
--- /dev/null
+++ b/src/Specials/HTMLForm/LanguageLookupWidgetField.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace Wikibase\Lexeme\Specials\HTMLForm;
+
+use Wikibase\Repo\Specials\HTMLForm\HTMLItemReferenceField;
+
+/**
+ * Passes LanguageLookupWidget instead of OOUI\TextInputWidget to the frontend
+ *
+ * @license GPL-2.0+
+ */
+class LanguageLookupWidgetField extends HTMLItemReferenceField {
+
+       protected function getInputWidget( $params ) {
+               return new LanguageLookupWidget( $params );
+       }
+
+}
diff --git a/src/Specials/SpecialNewLexeme.php 
b/src/Specials/SpecialNewLexeme.php
index 027d02b..c5af2b2 100644
--- a/src/Specials/SpecialNewLexeme.php
+++ b/src/Specials/SpecialNewLexeme.php
@@ -2,6 +2,7 @@
 
 namespace Wikibase\Lexeme\Specials;
 
+use OutputPage;
 use Status;
 use Wikibase\CopyrightMessageBuilder;
 use Wikibase\DataModel\Entity\EntityDocument;
@@ -11,6 +12,7 @@
 use Wikibase\DataModel\Term\TermList;
 use Wikibase\Lexeme\DataModel\Lexeme;
 use Wikibase\Lib\Store\EntityNamespaceLookup;
+use Wikibase\Lexeme\Specials\HTMLForm\LanguageLookupWidgetField;
 use Wikibase\Repo\Specials\HTMLForm\HTMLContentLanguageField;
 use Wikibase\Repo\Specials\HTMLForm\HTMLItemReferenceField;
 use Wikibase\Repo\Specials\HTMLForm\HTMLTrimmedTextField;
@@ -66,12 +68,6 @@
         */
        protected function getFormFields() {
                return [
-                       self::FIELD_LEMMA_LANGUAGE => [
-                               'name' => self::FIELD_LEMMA_LANGUAGE,
-                               'class' => HTMLContentLanguageField::class,
-                               'id' => 'wb-newlexeme-lemma-language',
-                               'label-message' => 
'wikibase-newlexeme-lemma-language',
-                       ],
                        self::FIELD_LEMMA => [
                                'name' => self::FIELD_LEMMA,
                                'class' => HTMLTrimmedTextField::class,
@@ -80,18 +76,24 @@
                                'placeholder-message' => 
'wikibase-lemma-edit-placeholder',
                                'label-message' => 'wikibase-newlexeme-lemma'
                        ],
+                       self::FIELD_LEMMA_LANGUAGE => [
+                               'name' => self::FIELD_LEMMA_LANGUAGE,
+                               'class' => HTMLContentLanguageField::class,
+                               'id' => 'wb-newlexeme-lemma-language',
+                               'label-message' => 
'wikibase-newlexeme-lemma-language',
+                       ],
+                       self::FIELD_LEXEME_LANGUAGE => [
+                               'name' => self::FIELD_LEXEME_LANGUAGE,
+                               'class' => LanguageLookupWidgetField::class,
+                               'id' => 'wb-newlexeme-lexeme-language',
+                               'label-message' => 
'wikibase-newlexeme-language',
+                               'required' => true,
+                       ],
                        self::FIELD_LEXICAL_CATEGORY => [
                                'name' => self::FIELD_LEXICAL_CATEGORY,
                                'class' => HTMLItemReferenceField::class,
                                'id' => 'wb-newlexeme-lexicalCategory',
                                'label-message' => 
'wikibase-newlexeme-lexicalcategory',
-                               'required' => true,
-                       ],
-                       self::FIELD_LEXEME_LANGUAGE => [
-                               'name' => self::FIELD_LEXEME_LANGUAGE,
-                               'class' => HTMLItemReferenceField::class,
-                               'id' => 'wb-newlexeme-lexeme-language',
-                               'label-message' => 
'wikibase-newlexeme-language',
                                'required' => true,
                        ]
                ];
@@ -163,4 +165,9 @@
                return [];
        }
 
+       protected function displayBeforeForm( OutputPage $output ) {
+               parent::displayBeforeForm( $output );
+               $output->addModules( 'wikibase.lexeme.special.NewLexeme' );
+       }
+
 }
diff --git a/src/WikibaseLexeme.hooks.php b/src/WikibaseLexeme.hooks.php
index 2c9a040..10c4762 100644
--- a/src/WikibaseLexeme.hooks.php
+++ b/src/WikibaseLexeme.hooks.php
@@ -3,6 +3,7 @@
 namespace Wikibase\Lexeme;
 
 use MediaWiki\MediaWikiServices;
+use ResourceLoader;
 
 /**
  * MediaWiki hook handlers for the Wikibase Lexeme extension.
@@ -76,4 +77,20 @@
                );
        }
 
+       public static function onResourceLoaderTestModules( array 
&$testModules, ResourceLoader $rl ) {
+               $testModules['qunit']['WikibaseLexeme.tests'] = [
+                       'scripts' => [
+                               
'tests/qunit/widgets/LanguageLookupWidget.tests.js',
+                       ],
+                       'dependencies' => [
+                               'wikibase.lexeme.widgets.LanguageLookupWidget',
+                               'oojs-ui'
+                       ],
+                       'localBasePath' => dirname( __DIR__ ),
+                       'remoteExtPath' => 'WikibaseLexeme',
+               ];
+
+               return true;
+       }
+
 }
diff --git 
a/tests/phpunit/mediawiki/Specials/HTMLForm/LanguageLookupWidgetFieldTest.php 
b/tests/phpunit/mediawiki/Specials/HTMLForm/LanguageLookupWidgetFieldTest.php
new file mode 100644
index 0000000..affd1a9
--- /dev/null
+++ 
b/tests/phpunit/mediawiki/Specials/HTMLForm/LanguageLookupWidgetFieldTest.php
@@ -0,0 +1,29 @@
+<?php
+
+namespace Wikibase\Lexeme\Tests\Specials\HTMLForm;
+
+use ReflectionClass;
+use Wikibase\Lexeme\Specials\HTMLForm\LanguageLookupWidget;
+use Wikibase\Lexeme\Specials\HTMLForm\LanguageLookupWidgetField;
+
+/**
+ * @covers Wikibase\Lexeme\Specials\HTMLForm\LanguageLookupWidgetField
+ *
+ * @group Wikibase
+ *
+ * @license GPL-2.0+
+ */
+class LanguageLookupWidgetFieldTest extends \PHPUnit_Framework_TestCase {
+
+       public function testGetInputWidget_returnsLanguageLookupWidget() {
+               $getInputWidget = ( new ReflectionClass( 
LanguageLookupWidgetField::class ) )
+                       ->getMethod( 'getInputWidget' );
+               $getInputWidget->setAccessible( true );
+
+               $this->assertInstanceOf(
+                       LanguageLookupWidget::class,
+                       $getInputWidget->invokeArgs( new 
LanguageLookupWidgetField( [ 'fieldname' => '' ] ), [ [] ] )
+               );
+       }
+
+}
diff --git a/tests/qunit/widgets/LanguageLookupWidget.tests.js 
b/tests/qunit/widgets/LanguageLookupWidget.tests.js
new file mode 100644
index 0000000..c5d9adf
--- /dev/null
+++ b/tests/qunit/widgets/LanguageLookupWidget.tests.js
@@ -0,0 +1,73 @@
+/**
+ * @license GPL-2.0+
+ */
+( function ( wb, $, QUnit ) {
+       QUnit.module( 'wikibase.lexeme.widgets.LanguageLookupWidget' );
+
+       var newInitializedLanguageLookupWidget = function () {
+               var widget = new wb.lexeme.widgets.LanguageLookupWidget();
+
+               widget.initialize( {
+                       apiUrl: '-',
+                       language: '-',
+                       timeout: 100
+               } );
+
+               return widget;
+       };
+
+       var stubWbsearchentitiesResponse = function ( response ) {
+               $.ajax = function () {
+                       var deferred = $.Deferred().resolve( response );
+                       return deferred.promise();
+               }
+       };
+
+       QUnit.test( 'getLookupRequest returns request results', function ( 
assert ) {
+               var widget = newInitializedLanguageLookupWidget(),
+                       searchEntitiesResults = [ { id: 'Q123', label: 
'English' }, { id: 'Q234', label: 'German' } ];
+
+               stubWbsearchentitiesResponse( { search: searchEntitiesResults } 
);
+
+               widget.getLookupRequest().done( function ( items ) {
+                       assert.deepEqual( items, searchEntitiesResults );
+               } );
+       } );
+
+       QUnit.test( 'getLookupMenuOptionsFromData returns suggestions from 
results', function ( assert ) {
+               var widget = newInitializedLanguageLookupWidget(),
+                       searchEntitiesResults = [ { id: 'Q123', label: 
'English' }, { id: 'Q234', label: 'German' } ],
+                       suggestions = widget.getLookupMenuOptionsFromData( 
searchEntitiesResults );
+
+               assert.equal( searchEntitiesResults.length, suggestions.length 
);
+               assert.equal( searchEntitiesResults[ 0 ].label, suggestions[ 0 
].label );
+               assert.equal( searchEntitiesResults[ 0 ].data, suggestions[ 0 
].id );
+               assert.equal( searchEntitiesResults[ 1 ].label, suggestions[ 1 
].label );
+               assert.equal( searchEntitiesResults[ 1 ].data, suggestions[ 1 
].id );
+       } );
+
+       QUnit.test( 'initialize throws error when required parameters are not 
provided', function ( assert ) {
+               var widget = new wb.lexeme.widgets.LanguageLookupWidget();
+
+               assert.throws( function () {
+                       widget.initialize( { apiUrl: null, language: 'en', 
timeout: 100 } );
+               } );
+               assert.throws( function () {
+                       widget.initialize( { apiUrl: 'some-url', language: 
null, timeout: 100 } );
+               } );
+               assert.throws( function () {
+                       widget.initialize( { apiUrl: 'some-url', language: 
'en', timeout: null } );
+               } );
+       } );
+
+       QUnit.test( 'getLookupRequest if the LanguageLookupWidget was not 
initialized', function ( assert ) {
+               var widget = new wb.lexeme.widgets.LanguageLookupWidget();
+
+               stubWbsearchentitiesResponse( { search: [] } );
+
+               assert.throws( function () {
+                       widget.getLookupRequest();
+               } );
+       } )
+
+}( wikibase, jQuery, QUnit ) );

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

Gerrit-MessageType: merged
Gerrit-Change-Id: I6ed726c3cfb223705c466548d856e13e5ab4ac37
Gerrit-PatchSet: 7
Gerrit-Project: mediawiki/extensions/WikibaseLexeme
Gerrit-Branch: master
Gerrit-Owner: Jakob <[email protected]>
Gerrit-Reviewer: Aleksey Bekh-Ivanov (WMDE) <[email protected]>
Gerrit-Reviewer: Jakob <[email protected]>
Gerrit-Reviewer: Jonas Kress (WMDE) <[email protected]>
Gerrit-Reviewer: Ladsgroup <[email protected]>
Gerrit-Reviewer: Thiemo Mättig (WMDE) <[email protected]>
Gerrit-Reviewer: WMDE-leszek <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

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

Reply via email to