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

Change subject: LemmaHeader language and lexical category formatting
......................................................................


LemmaHeader language and lexical category formatting

Bug: T168298
Bug: T168300
Change-Id: I3825926fa02a42fb941a2d581f61246bd8268ca2
---
M package.json
M resources/widgets/ItemSelectorWrapper.js
M resources/widgets/LanguageAndLexicalCategoryWidget.js
M resources/widgets/LexemeHeader.js
M resources/widgets/LexemeHeader.newLexemeHeader.js
M resources/widgets/LexemeHeader.newLexemeHeaderStore.js
M src/View/LexemeView.php
M src/View/LexemeViewFactory.php
M tests/browser/features/step_definitions/lexeme_header_steps.rb
M tests/jasmine/LanguageAndLexicalCategoryWidget.spec.js
M tests/jasmine/LexemeHeaderStore.spec.js
M tests/phpunit/mediawiki/View/LexemeViewTest.php
12 files changed, 310 insertions(+), 97 deletions(-)

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



diff --git a/package.json b/package.json
index 7c6d348..af5c507 100644
--- a/package.json
+++ b/package.json
@@ -11,6 +11,7 @@
     "grunt-jasmine-nodejs": "^1.6.0",
     "grunt-jsonlint": "1.0.7",
     "jasmine": "^2.6.0",
+    "jquery": "^3.2.1",
     "jsdom": "^11.1.0",
     "jsdom-global": "^3.0.2",
     "module-alias": "^2.0.0",
@@ -28,7 +29,7 @@
     "wikibase.lexeme.widgets.LemmaWidget.newLemmaWidget": 
"./resources/widgets/LemmaWidget.newLemmaWidget.js",
     "wikibase.lexeme.widgets.LexemeHeader.newLexemeHeaderStore": 
"./resources/widgets/LexemeHeader.newLexemeHeaderStore.js",
     "wikibase.lexeme.widgets.LanguageAndLexicalCategoryWidget": 
"./resources/widgets/LanguageAndLexicalCategoryWidget.js",
-    "wikibase.lexeme.widgets.ItemSelectorWrapper" : 
"./resources/widgets/ItemSelectorWrapper.js",
+    "wikibase.lexeme.widgets.ItemSelectorWrapper": 
"./resources/widgets/ItemSelectorWrapper.js",
     "wikibase.lexeme.widgets.LexemeHeader.newLexemeHeader": 
"./resources/widgets/LexemeHeader.newLexemeHeader.js",
     "wikibase.lexeme.datamodel.Lemma": "./resources/datamodel/Lemma.js"
   }
diff --git a/resources/widgets/ItemSelectorWrapper.js 
b/resources/widgets/ItemSelectorWrapper.js
index 0f8274a..bdd7090 100644
--- a/resources/widgets/ItemSelectorWrapper.js
+++ b/resources/widgets/ItemSelectorWrapper.js
@@ -1,40 +1,68 @@
 module.exports = ( function ( mw ) {
        'use strict';
 
-       return {
-               props: [ 'value' ],
-               template: '<input>',
-               mounted: function () {
-                       var vm = this,
-                               repoConfig = mw.config.get( 'wbRepo' ),
-                               repoApiUrl = repoConfig.url + 
repoConfig.scriptPath + '/api.php',
-                               expertType = 'item',
-                               $input = $( this.$el );
+       /**
+        * @param {wikibase.api.RepoApi} api
+        * @param {string} id
+        * @return {jquery.Promise}
+        */
+       function formatEntityLabel( api, id ) {
+               var deferred = $.Deferred(),
+                       dataValue = { value: { id: id }, type: 
'wikibase-entityid' };
 
-                       $input.val( this.value );
+               api.formatValue(
+                       dataValue,
+                       {},
+                       'wikibase-item',
+                       'text/plain',
+                       ''
+               ).then( function ( response ) {
+                       deferred.resolve( response.result );
+               } );
 
-                       $input.entityselector( {
-                               url: repoApiUrl,
-                               type: expertType,
-                               selectOnAutocomplete: true
-                       } );
+               return deferred.promise();
+       }
 
-                       $input.on( 'entityselectorselected', function ( e ) {
-                               var entitySelector = $( vm.$el ).data( 
'entityselector' ),
-                                       selectedEntity = 
entitySelector.selectedEntity();
+       return function ( api ) {
+               return {
+                       props: [ 'value' ],
+                       template: '<input>',
+                       mounted: function () {
+                               var vm = this,
+                                       repoConfig = mw.config.get( 'wbRepo' ),
+                                       repoApiUrl = repoConfig.url + 
repoConfig.scriptPath + '/api.php',
+                                       expertType = 'item',
+                                       $input = $( this.$el );
 
-                               var value = selectedEntity ? selectedEntity.id 
: '';
+                               formatEntityLabel( api, this.value ).then( 
function ( label ) {
+                                       $input.val( label );
 
-                               vm.$emit( 'input', value );
-                       } );
-               },
-               watch: {
-                       value: function ( value ) {
-                               $( this.$el ).data( 'entityselector' 
).selectedEntity( value );
+                                       $input.entityselector( {
+                                               url: repoApiUrl,
+                                               type: expertType,
+                                               selectOnAutocomplete: true
+                                       } );
+
+                                       $input.on( 'entityselectorselected', 
function ( e ) {
+                                               var entitySelector = $( vm.$el 
).data( 'entityselector' ),
+                                                       selectedEntity = 
entitySelector.selectedEntity();
+
+                                               var value = selectedEntity ? 
selectedEntity.id : '';
+
+                                               vm.$emit( 'input', value );
+                                       } );
+                               } );
+
+                       },
+                       watch: {
+                               value: function ( value ) {
+                                       $( this.$el ).data( 'entityselector' 
).selectedEntity( value );
+                               }
+                       },
+                       destroyed: function () {
+                               $( this.$el ).data( 'entityselector' 
).destroy();
                        }
-               },
-               destroyed: function () {
-                       $( this.$el ).data( 'entityselector' ).destroy();
-               }
+               };
        };
+
 } )( mediaWiki );
diff --git a/resources/widgets/LanguageAndLexicalCategoryWidget.js 
b/resources/widgets/LanguageAndLexicalCategoryWidget.js
index 6ebf943..5534d33 100644
--- a/resources/widgets/LanguageAndLexicalCategoryWidget.js
+++ b/resources/widgets/LanguageAndLexicalCategoryWidget.js
@@ -7,20 +7,29 @@
         * @callback wikibase.lexeme.widgets.LanguageAndLexicalCategoryWidget
         *
         * @param {string} template - template string or selector
+        * @param {wikibase.api.RepoApi} repoApi
         * @param {Object} messages - mw.messages localization service
         */
-       return function ( template, messages ) {
+       return function ( template, api, messages ) {
                return {
                        props: [ 'language', 'lexicalCategory', 'inEditMode', 
'isSaving' ],
                        template: template,
                        components: {
-                               'item-selector': ItemSelectorWrapper
+                               'item-selector': ItemSelectorWrapper( api )
                        },
 
                        filters: {
                                message: function ( key ) {
                                        return messages.get( key );
                                }
+                       },
+                       computed: {
+                               formattedLanguage: function () {
+                                       return this.$store.state.languageLink;
+                               },
+                               formattedLexicalCategory: function () {
+                                       return 
this.$store.state.lexicalCategoryLink;
+                               }
                        }
                };
        };
diff --git a/resources/widgets/LexemeHeader.js 
b/resources/widgets/LexemeHeader.js
index 3f59f37..850d03a 100644
--- a/resources/widgets/LexemeHeader.js
+++ b/resources/widgets/LexemeHeader.js
@@ -26,11 +26,18 @@
 
        var baseRevId = mw.config.get( 'wgCurRevisionId' );
 
-       var store = new Vuex.Store( newLexemeHeaderStore( repoApi, lexeme, 
baseRevId ) );
+       var store = new Vuex.Store( newLexemeHeaderStore(
+               repoApi,
+               lexeme,
+               baseRevId,
+               $( '.language-lexical-category-widget_language' ).html(),
+               $( '.language-lexical-category-widget_lexical-category' ).html()
+       ) );
 
        var lemmaWidget = newLemmaWidget( '#lemma-widget-vue-template', 
mw.messages );
        var languageAndLexicalCategoryWidget = 
newLanguageAndLexicalCategoryWidget(
                '#language-and-lexical-category-widget-vue-template',
+               repoApi,
                mw.messages
        );
        var app = new Vue( newLexemeHeader(
diff --git a/resources/widgets/LexemeHeader.newLexemeHeader.js 
b/resources/widgets/LexemeHeader.newLexemeHeader.js
index ab6362d..ce42bda 100644
--- a/resources/widgets/LexemeHeader.newLexemeHeader.js
+++ b/resources/widgets/LexemeHeader.newLexemeHeader.js
@@ -24,6 +24,7 @@
                return {
                        el: element,
                        template: template,
+                       store: store,
 
                        data: {
                                isInitialized: true,
diff --git a/resources/widgets/LexemeHeader.newLexemeHeaderStore.js 
b/resources/widgets/LexemeHeader.newLexemeHeaderStore.js
index abec000..3372425 100644
--- a/resources/widgets/LexemeHeader.newLexemeHeaderStore.js
+++ b/resources/widgets/LexemeHeader.newLexemeHeaderStore.js
@@ -25,21 +25,47 @@
        }
 
        /**
+        * @param {wikibase.api.RepoApi} api
+        * @param {string} id
+        * @return {jquery.Promise}
+        */
+       function formatEntityId( api, id ) {
+               var deferred = $.Deferred(),
+                       dataValue = { value: { id: id }, type: 
'wikibase-entityid' };
+
+               api.formatValue(
+                       dataValue,
+                       {},
+                       'wikibase-item',
+                       'text/html',
+                       ''
+               ).then( function ( d ) {
+                       deferred.resolve( d.result );
+               } );
+
+               return deferred.promise();
+       }
+
+       /**
         * @callback wikibase.lexeme.widgets.LexemeHeader.newLemmaWidgetStore
         * @param {wikibase.api.RepoApi} repoApi
         * @param {wikibase.lexeme.datamodel.Lexeme} lexeme
         * @param {int} baseRevId
+        * @param {string} languageLink HTML
+        * @param {string} lexicalCategoryLink HTML
         */
-       return function ( repoApi, lexeme, baseRevId ) {
+       return function ( repoApi, lexeme, baseRevId, languageLink, 
lexicalCategoryLink ) {
                return {
-                       strict: true, //FIXME make it configurable
+                       strict: true, // FIXME make it configurable
                        state: {
                                isSaving: false,
                                baseRevId: baseRevId,
                                id: lexeme.id,
                                lemmas: lexeme.lemmas,
                                language: lexeme.language,
-                               lexicalCategory: lexeme.lexicalCategory
+                               languageLink: languageLink,
+                               lexicalCategory: lexeme.lexicalCategory,
+                               lexicalCategoryLink: lexicalCategoryLink
                        },
                        mutations: {
                                updateLemmas: function ( state, newLemmas ) {
@@ -47,6 +73,14 @@
                                },
                                updateRevisionId: function ( state, revisionId 
) {
                                        state.baseRevId = revisionId;
+                               },
+                               updateLanguage: function ( state, data ) {
+                                       state.language = data.id;
+                                       state.languageLink = data.link;
+                               },
+                               updateLexicalCategory: function ( state, data ) 
{
+                                       state.lexicalCategory = data.id;
+                                       state.lexicalCategoryLink = data.link;
                                },
                                startSaving: function ( state ) {
                                        state.isSaving = true;
@@ -65,21 +99,29 @@
                                        var requestLemmas = getRequestLemmas( 
context.state.lemmas, lexeme.lemmas );
 
                                        var data = {
-                                               lemmas: requestLemmas,
-                                               language: lexeme.language,
-                                               lexicalCategory: 
lexeme.lexicalCategory
-                                       };
+                                                       lemmas: requestLemmas,
+                                                       language: 
lexeme.language,
+                                                       lexicalCategory: 
lexeme.lexicalCategory
+                                               },
+                                               saveRequest = 
repoApi.editEntity(
+                                                       context.state.id,
+                                                       context.state.baseRevId,
+                                                       data,
+                                                       false //clear
+                                               );
 
-                                       var clear = false;
-                                       return repoApi.editEntity(
-                                               context.state.id,
-                                               context.state.baseRevId,
-                                               data,
-                                               clear
-                                       ).then( function ( response ) {
-                                               context.commit( 
'updateRevisionId', response.entity.lastrevid );
-                                               //TODO:  update state of 
lemmas, language and lexicalCategory if needed
-                                               context.commit( 'updateLemmas', 
response.entity.lemmas || lexeme.lemmas );
+                                       return $.when(
+                                               saveRequest,
+                                               formatEntityId( repoApi, 
lexeme.language ),
+                                               formatEntityId( repoApi, 
lexeme.lexicalCategory )
+                                       ).then( function ( response, 
formattedLanguage, formattedLexicalCategory ) {
+                                               context.commit( 
'updateRevisionId', response[ 0 ].entity.lastrevid );
+                                               // TODO: Update state of 
lemmas, language and lexicalCategory if needed.
+                                               // Note: API response does not 
contain lemma.
+                                               context.commit( 'updateLemmas', 
response[ 0 ].entity.lemmas || lexeme.lemmas );
+                                               context.commit( 
'updateLanguage', { id: lexeme.language, link: formattedLanguage } );
+                                               context.commit( 
'updateLexicalCategory', { id: lexeme.lexicalCategory, link: 
formattedLexicalCategory } );
+
                                                context.commit( 'finishSaving' 
);
                                        } ).catch( function () {
                                                context.commit( 'finishSaving' 
);
diff --git a/src/View/LexemeView.php b/src/View/LexemeView.php
index a242cea..e51f8d7 100644
--- a/src/View/LexemeView.php
+++ b/src/View/LexemeView.php
@@ -7,6 +7,7 @@
 use Message;
 use Wikibase\DataModel\Entity\EntityDocument;
 use Wikibase\DataModel\Entity\ItemId;
+use Wikibase\DataModel\Services\EntityId\EntityIdFormatter;
 use Wikibase\DataModel\Services\Lookup\LabelDescriptionLookup;
 use Wikibase\DataModel\Services\Lookup\LabelDescriptionLookupException;
 use Wikibase\DataModel\Term\Term;
@@ -55,6 +56,11 @@
        private $labelDescriptionLookup;
 
        /**
+        * @var EntityIdFormatter
+        */
+       private $idFormatter;
+
+       /**
         * @param TemplateFactory $templateFactory
         * @param EntityTermsView $entityTermsView
         * @param LanguageDirectionalityLookup $languageDirectionalityLookup
@@ -64,6 +70,7 @@
         * @param StatementSectionsView $statementSectionsView
         * @param HtmlTermRenderer $htmlTermRenderer
         * @param LabelDescriptionLookup $labelDescriptionLookup
+        * @param EntityIdFormatter $idFormatter
         */
        public function __construct(
                TemplateFactory $templateFactory,
@@ -74,7 +81,8 @@
                SensesView $sensesView,
                StatementSectionsView $statementSectionsView,
                HtmlTermRenderer $htmlTermRenderer,
-               LabelDescriptionLookup $labelDescriptionLookup
+               LabelDescriptionLookup $labelDescriptionLookup,
+               EntityIdFormatter $idFormatter
        ) {
                parent::__construct(
                        $templateFactory,
@@ -88,6 +96,7 @@
                $this->statementSectionsView = $statementSectionsView;
                $this->htmlTermRenderer = $htmlTermRenderer;
                $this->labelDescriptionLookup = $labelDescriptionLookup;
+               $this->idFormatter = $idFormatter;
        }
 
        /**
@@ -277,11 +286,11 @@
                        <lemma-widget :lemmas="lemmas" :inEditMode="inEditMode" 
:isSaving="isSaving"></lemma-widget>
                </div>
                <div class="lemma-widget_controls" v-if="isInitialized" >
-                       <button type="button" class="lemma-widget_edit" 
v-if="!inEditMode" 
+                       <button type="button" class="lemma-widget_edit" 
v-if="!inEditMode"
                                :disabled="isSaving" 
v-on:click="edit">{{'wikibase-edit'|message}}</button>
-                       <button type="button" class="lemma-widget_save" 
v-if="inEditMode" 
+                       <button type="button" class="lemma-widget_save" 
v-if="inEditMode"
                                :disabled="isSaving" 
v-on:click="save">{{'wikibase-save'|message}}</button>
-                       <button type="button" class="lemma-widget_cancel" 
v-if="inEditMode" 
+                       <button type="button" class="lemma-widget_cancel" 
v-if="inEditMode"
                                :disabled="isSaving"  
v-on:click="cancel">{{'wikibase-cancel'|message}}</button>
                </div>
        </h1>
@@ -301,11 +310,12 @@
        <div v-if="!inEditMode">
                <div>
                        <span>{{'wikibase-lexeme-language'|message}}</span>
-                       <span 
class="language-lexical-category-widget_language">{{language}}</span>
+                       <span class="language-lexical-category-widget_language" 
v-html="formattedLanguage"></span>
                </div>
                <div>
                        
<span>{{'wikibase-lexeme-lexical-category'|message}}</span>
-                       <span 
class="language-lexical-category-widget_lexical-category">{{lexicalCategory}}</span>
+                       <span 
class="language-lexical-category-widget_lexical-category"
+                               v-html="formattedLexicalCategory"></span>
                </div>
        </div>
        <div v-else>
@@ -343,20 +353,20 @@
                                <span class="lemma-widget_lemma-value-label">
                                        
{{'wikibase-lemma-field-lemma-label'|message}}
                                </span>
-                               <input size="1" 
class="lemma-widget_lemma-value-input" 
+                               <input size="1" 
class="lemma-widget_lemma-value-input"
                                        v-model="lemma.value" 
:disabled="isSaving">
                                <span class="lemma-widget_lemma-language-label">
                                        
{{'wikibase-lemma-field-language-label'|message}}
                                </span>
-                               <input size="1" 
class="lemma-widget_lemma-language-input" 
+                               <input size="1" 
class="lemma-widget_lemma-language-input"
                                        v-model="lemma.language" 
:disabled="isSaving">
-                               <button class="lemma-widget_lemma-remove" 
v-on:click="remove(lemma)" 
+                               <button class="lemma-widget_lemma-remove" 
v-on:click="remove(lemma)"
                                        :disabled="isSaving" 
:title="'wikibase-remove'|message">
                                        &times;
                                </button>
                        </li>
                        <li>
-                               <button type="button" class="lemma-widget_add" 
v-on:click="add" 
+                               <button type="button" class="lemma-widget_add" 
v-on:click="add"
                                        :disabled="isSaving" 
:title="'wikibase-add'|message">+</button>
                        </li>
                </ul>
@@ -405,14 +415,21 @@
        protected function renderLanguageAndLexicalCategoryWidget( Lexeme 
$lexeme ) {
                $templating = new Templating();
 
+               $languageId = $lexeme->getLanguage();
+               $lexicalCategoryId = $lexeme->getLexicalCategory();
+
                $result = $templating->render(
                        
$this->getRawLanguageAndLexicalCategoryWidgetVueTemplate(),
                        [
                                'isInitialized' => false,
                                'inEditMode' => false,
                                'isSaving' => false,
-                               'language' => 
$lexeme->getLanguage()->getSerialization(),
-                               'lexicalCategory' => 
$lexeme->getLexicalCategory()->getSerialization()
+                               'formattedLanguage' => 
$this->idFormatter->formatEntityId( $languageId ),
+                               'language' => $languageId->getSerialization(),
+                               'formattedLexicalCategory' => 
$this->idFormatter->formatEntityId(
+                                       $lexicalCategoryId
+                               ),
+                               'lexicalCategory' => 
$lexicalCategoryId->getSerialization()
                        ],
                        [
                                'message' => function ( $key ) {
diff --git a/src/View/LexemeViewFactory.php b/src/View/LexemeViewFactory.php
index a24b258..62d31c3 100644
--- a/src/View/LexemeViewFactory.php
+++ b/src/View/LexemeViewFactory.php
@@ -112,11 +112,13 @@
                        new LanguageNameLookup( $this->languageCode )
                );
 
+               $idLinkFormatter = $this->entityIdFormatterFactory
+                       ->getEntityIdFormatter( 
$retrievingLabelDescriptionLookup );
+
                $formsView = new FormsView(
                        $localizedTextProvider,
                        $templateFactory,
-                       $this->entityIdFormatterFactory
-                               ->getEntityIdFormatter( 
$retrievingLabelDescriptionLookup ),
+                       $idLinkFormatter,
                        $statementGroupListView
                );
 
@@ -137,7 +139,8 @@
                        $sensesView,
                        $statementSectionsView,
                        $htmlTermRenderer,
-                       $retrievingLabelDescriptionLookup
+                       $retrievingLabelDescriptionLookup,
+                       $idLinkFormatter
                );
        }
 
diff --git a/tests/browser/features/step_definitions/lexeme_header_steps.rb 
b/tests/browser/features/step_definitions/lexeme_header_steps.rb
index 5b3bd1b..d0cf23f 100644
--- a/tests/browser/features/step_definitions/lexeme_header_steps.rb
+++ b/tests/browser/features/step_definitions/lexeme_header_steps.rb
@@ -1,32 +1,31 @@
 When(/^I click the lexeme header edit button$/) do
   on(LexemePage).lexeme_header.edit_element.when_visible.click
+  on(LexemePage).ajax_wait
 end
 
 When(/^I enter the test item id into the lexeme language field$/) do
-  on(LexemePage).lexeme_header.lexeme_language_input = @item_under_test['id']
+  on(LexemePage).lexeme_header.lexeme_language_input = 
@item_under_test['label']
   on(LexemePage).ajax_wait
 end
 
 When(/^I click the lexeme header save button$/) do
   on(LexemePage).lexeme_header.save_element.when_visible.click
-  Watir::Wait.until(timeout = 5) do
-    on(LexemePage).lexeme_header.edit_element.visible?
-  end
+  on(LexemePage).ajax_wait
 end
 
 Then(/^I should see the item in the lexeme language field$/) do
   expect(
     on(LexemePage).lexeme_header.lexeme_language_element.text
-  ).to eq @item_under_test['id']
+  ).to eq @item_under_test['label']
 end
 
 When(/^I enter the test item id into the lexical category field$/) do
-  on(LexemePage).lexeme_header.lexical_category_input = @item_under_test['id']
+  on(LexemePage).lexeme_header.lexical_category_input = 
@item_under_test['label']
   on(LexemePage).ajax_wait
 end
 
 Then(/^I should see the item in the lexical category field$/) do
   expect(
     on(LexemePage).lexeme_header.lexical_category_element.text
-  ).to eq @item_under_test['id']
+  ).to eq @item_under_test['label']
 end
diff --git a/tests/jasmine/LanguageAndLexicalCategoryWidget.spec.js 
b/tests/jasmine/LanguageAndLexicalCategoryWidget.spec.js
index f554092..32b9e96 100644
--- a/tests/jasmine/LanguageAndLexicalCategoryWidget.spec.js
+++ b/tests/jasmine/LanguageAndLexicalCategoryWidget.spec.js
@@ -24,8 +24,11 @@
                        lexicalCategory = 'Q234',
                        widget = newWidget( language, lexicalCategory );
 
-               expect( widget.$el.textContent, 'to contain', language );
-               expect( widget.$el.textContent, 'to contain', lexicalCategory );
+               expect( widget.$el.textContent, 'to contain', 'Link for ' + 
language );
+               expect( widget.$el.textContent, 'to contain', 'Link for ' + 
lexicalCategory );
+
+               expect( widget.$el, 'to contain elements matching', 
'.language-link' );
+               expect( widget.$el, 'to contain elements matching', 
'.lexical-category-link' );
        } );
 
        it( 'switches to edit mode and back', function ( done ) {
@@ -54,13 +57,19 @@
        } );
 
        function newWidget( language, lexicalCategory ) {
-               var LanguageAndLexicalCategoryWidget = Vue.extend( 
newLanguageAndLexicalCategoryWidget( getTemplate(), {
+               var LanguageAndLexicalCategoryWidget = Vue.extend( 
newLanguageAndLexicalCategoryWidget( getTemplate(), {}, {
                        get: function ( key ) {
                                return key;
                        }
                } ) );
 
                return new LanguageAndLexicalCategoryWidget( {
+                       store: {
+                               state: {
+                                       languageLink: '<a href="#" 
class="language-link">Link for ' + language + '</a>',
+                                       lexicalCategoryLink: '<a href="#" 
class="lexical-category-link">Link for ' + lexicalCategory + '</a>'
+                               }
+                       },
                        propsData: {
                                language: language,
                                lexicalCategory: lexicalCategory,
@@ -75,11 +84,11 @@
                        + '<div v-if="!inEditMode">'
                        + '<div>'
                        + 
'<span>{{\'wikibase-lexeme-language\'|message}}</span>'
-                       + '<span>{{language}}</span>'
+                       + '<span v-html="formattedLanguage"></span>'
                        + '</div>'
                        + '<div>'
                        + 
'<span>{{\'wikibase-lexeme-lexical-category\'|message}}</span>'
-                       + '<span>{{lexicalCategory}}</span>'
+                       + '<span v-html="formattedLexicalCategory"></span>'
                        + '</div>'
                        + '</div>'
                        + '<div v-else>'
diff --git a/tests/jasmine/LexemeHeaderStore.spec.js 
b/tests/jasmine/LexemeHeaderStore.spec.js
index 2d3b91f..19796b7 100644
--- a/tests/jasmine/LexemeHeaderStore.spec.js
+++ b/tests/jasmine/LexemeHeaderStore.spec.js
@@ -5,11 +5,13 @@
        var sinon = require( 'sinon' );
        var expect = require( 'unexpected' ).clone();
 
+       global.$ = require( 'jquery' ); // eslint-disable-line 
no-restricted-globals
+
        /** @type {wikibase.lexeme.widgets.LexemeHeader.newLexemeHeaderStore} */
        var newLexemeHeaderStore = require( 
'wikibase.lexeme.widgets.LexemeHeader.newLexemeHeaderStore' );
        var Lemma = require( 'wikibase.lexeme.datamodel.Lemma' );
 
-       var mutations = newLexemeHeaderStore( {}, [], '', 0 ).mutations;
+       var mutations = newLexemeHeaderStore( {}, {}, 0, 'Some language', 'Some 
category' ).mutations;
 
        it( 'mutation startSaving switches the isSaving flag to true', function 
() {
                var state = { isSaving: false };
@@ -33,6 +35,24 @@
                mutations.updateRevisionId( state, 2 );
 
                expect( state.baseRevId, 'to be', 2 );
+       } );
+
+       it( 'mutation updateLanguage changes language and languageLink to given 
values', function () {
+               var state = { language: 'Q123', languageLink: '<a>English</a>' 
};
+
+               mutations.updateLanguage( state, { id: 'Q777', link: 
'<a>Finnish</a>' } );
+
+               expect( state.language, 'to be', 'Q777' );
+               expect( state.languageLink, 'to be', '<a>Finnish</a>' );
+       } );
+
+       it( 'mutation updateLanguage changes lexical category and the link to 
given values', function () {
+               var state = { language: 'Q123', languageLink: '<a>noun</a>' };
+
+               mutations.updateLanguage( state, { id: 'Q999', link: 
'<a>verb</a>' } );
+
+               expect( state.language, 'to be', 'Q999' );
+               expect( state.languageLink, 'to be', '<a>verb</a>' );
        } );
 
        function newTestAction( done ) {
@@ -65,7 +85,7 @@
                                                        expect( 
mutation.payload, 'to equal', payload );
                                                }
                                        } catch ( error ) {
-                                               done( error );
+                                               done.fail( 
error.getErrorMessage() );
                                        }
 
                                        count++;
@@ -87,34 +107,43 @@
        }
 
        it(
-               'action save on success mutates the state to start saving, 
updates revision, updates lemmas and finishes saving',
+               'action save on success mutates the state to start saving, 
updates state and finishes saving',
                function ( done ) {
                        var state = { isSaving: false, baseRevId: 1, lemmas: [] 
};
 
                        var newRevisionId = 2;
-                       var response = {
+                       var response = [ {
                                entity: {
                                        lastrevid: newRevisionId,
                                        lemmas: [ { value: 'lemma1', language: 
'en' } ]
                                }
-                       };
+                       } ];
 
                        var repoApi = {
                                editEntity: function ( id, baseRevId, data, 
clear ) {
                                        return Promise.resolve( response );
+                               },
+                               formatValue: function ( dataValue, options, 
dataType, outputFormat, propertyId ) {
+                                       return Promise.resolve( { result: 'Link 
for ' + dataValue.value.id } );
                                }
                        };
 
-                       var actions = newLexemeHeaderStore( repoApi, [], '', 0 
).actions;
+                       var actions = newLexemeHeaderStore( repoApi, {}, 0, 
'Some language', 'Some category' ).actions;
 
                        newTestAction( done ).test(
                                actions.save,
-                               { lemmas: [ new Lemma( 'lemma1', 'en' ) ] },
+                               {
+                                       lemmas: [ new Lemma( 'lemma1', 'en' ) ],
+                                       language: 'Q123',
+                                       lexicalCategory: 'Q234'
+                               },
                                state,
                                [
                                        { type: 'startSaving' },
                                        { type: 'updateRevisionId', payload: 
newRevisionId },
                                        { type: 'updateLemmas', payload: [ { 
value: 'lemma1', language: 'en' } ] },
+                                       { type: 'updateLanguage', payload: { 
id: 'Q123', link: 'Link for Q123' } },
+                                       { type: 'updateLexicalCategory', 
payload: { id: 'Q234', link: 'Link for Q234' } },
                                        { type: 'finishSaving' }
                                ]
                        );
@@ -126,22 +155,35 @@
                function ( done ) {
                        var baseRevisionId = 0;
                        var entityId = 'L1';
-                       var state = { id: entityId, isSaving: false, baseRevId: 
baseRevisionId, lemmas: [] };
+                       var state = {
+                               id: entityId,
+                               isSaving: false,
+                               baseRevId: baseRevisionId,
+                               lemmas: [],
+                               language: 'Q1',
+                               languageLink: 'Some language',
+                               lexicalCategory: 'Q2',
+                               lexicalCategoryLink: 'Some category'
+                       };
 
                        var newRevisionId = 2;
 
-                       var response = {
+                       var response = [ {
                                entity: {
                                        lastrevid: newRevisionId,
                                        lemmas: [ { value: 'lemma1', language: 
'en' } ]
                                }
-                       };
+                       } ];
 
                        var editEntity = function ( id, baseRevId, data, clear 
) {
                                return Promise.resolve( response );
                        };
+                       var formatValue = function ( dataValue, options, 
dataType, outputFormat, propertyId ) {
+                               return Promise.resolve( { result: 'Link for ' + 
dataValue.value.id } );
+                       };
                        var repoApi = {
-                               editEntity: sinon.spy( editEntity )
+                               editEntity: sinon.spy( editEntity ),
+                               formatValue: sinon.spy( formatValue )
                        };
 
                        var lexemeToSave = {
@@ -150,7 +192,7 @@
                                lexicalCategory: 'Q234'
                        };
 
-                       var actions = newLexemeHeaderStore( repoApi, { id: 
entityId }, baseRevisionId ).actions;
+                       var actions = newLexemeHeaderStore( repoApi, { id: 
entityId, language: 'Q1', lexicalCategory: 'Q2' }, baseRevisionId, 'Some 
language', 'Some category' ).actions;
                        newTestAction( done ).applyWithMutations(
                                actions.save,
                                lexemeToSave,
@@ -159,9 +201,34 @@
                        ).then( function () {
                                expect( newRevisionId, 'to equal', 
state.baseRevId );
                                expect( [ { value: 'lemma1', language: 'en' } 
], 'to equal', state.lemmas );
+                               expect( 'Q123', 'to equal', state.language );
+                               expect( 'Link for Q123', 'to equal', 
state.languageLink );
+                               expect( 'Q234', 'to equal', 
state.lexicalCategory );
+                               expect( 'Link for Q234', 'to equal', 
state.lexicalCategoryLink );
                                expect( state.isSaving, 'not to be ok' );
 
                                sinon.assert.calledWith( repoApi.editEntity, 
entityId, baseRevisionId, lexemeToSave, false );
+                               expect(
+                                       repoApi.formatValue.withArgs(
+                                               { type: 'wikibase-entityid', 
value: { id: 'Q123' } },
+                                               {},
+                                               'wikibase-item',
+                                               'text/html',
+                                               ''
+                                       ).called,
+                                       'to be true'
+                               );
+                               expect(
+                                       repoApi.formatValue.withArgs(
+                                               { type: 'wikibase-entityid', 
value: { id: 'Q234' } },
+                                               {},
+                                               'wikibase-item',
+                                               'text/html',
+                                               ''
+                                       ).called,
+                                       'to be true'
+                               );
+
                                done();
                        } );
                }
@@ -172,22 +239,27 @@
                function ( done ) {
                        var baseRevisionId = 1;
                        var entityId = 'L1';
-                       var state = { id: entityId, isSaving: false, baseRevId: 
baseRevisionId, lemmas: [ new Lemma( 'a lemma', 'en' ) ] };
+                       var state = { id: entityId, isSaving: false, baseRevId: 
baseRevisionId, lemmas: [ new Lemma( 'a lemma', 'en' ) ], language: 'Q1', 
languageLink: 'Some language' };
 
                        var newRevisionId = 2;
 
-                       var response = {
+                       var response = [ {
                                entity: {
                                        lastrevid: newRevisionId,
                                        lemmas: []
                                }
-                       };
+                       } ];
 
                        var editEntity = function ( id, baseRevId, data, clear 
) {
                                return Promise.resolve( response );
                        };
+                       var formatValue = function ( dataValue, options, 
dataType, outputFormat, propertyId ) {
+                               return Promise.resolve( { result: 'some 
formatted item' } );
+                       };
+
                        var repoApi = {
-                               editEntity: sinon.spy( editEntity )
+                               editEntity: sinon.spy( editEntity ),
+                               formatValue: sinon.spy( formatValue )
                        };
 
                        var lexemeToSave = {
@@ -201,7 +273,7 @@
                                lexicalCategory: 'Q234'
                        };
 
-                       var actions = newLexemeHeaderStore( repoApi, { id: 
entityId }, baseRevisionId ).actions;
+                       var actions = newLexemeHeaderStore( repoApi, { id: 
entityId }, baseRevisionId, 'Some language', 'Some category' ).actions;
                        newTestAction( done ).applyWithMutations(
                                actions.save,
                                lexemeToSave,
diff --git a/tests/phpunit/mediawiki/View/LexemeViewTest.php 
b/tests/phpunit/mediawiki/View/LexemeViewTest.php
index 696e1d9..34ebf24 100644
--- a/tests/phpunit/mediawiki/View/LexemeViewTest.php
+++ b/tests/phpunit/mediawiki/View/LexemeViewTest.php
@@ -5,6 +5,7 @@
 use InvalidArgumentException;
 use PHPUnit_Framework_TestCase;
 use Wikibase\DataModel\Entity\EntityDocument;
+use Wikibase\DataModel\Entity\EntityId;
 use Wikibase\DataModel\Entity\ItemId;
 use Wikibase\DataModel\Entity\PropertyId;
 use Wikibase\DataModel\Services\Lookup\LabelDescriptionLookup;
@@ -17,6 +18,7 @@
 use Wikibase\Lexeme\View\FormsView;
 use Wikibase\Lexeme\View\SensesView;
 use Wikibase\Lexeme\View\LexemeView;
+use Wikibase\Lib\EntityIdHtmlLinkFormatter;
 use Wikibase\Lib\LanguageNameLookup;
 use Wikibase\Repo\ParserOutput\FallbackHintHtmlTermRenderer;
 use Wikibase\View\EntityTermsView;
@@ -137,6 +139,16 @@
                        new LanguageNameLookup( 'en' )
                );
 
+               $linkFormatter = $this->getMockBuilder( 
EntityIdHtmlLinkFormatter::class )
+                       ->disableOriginalConstructor()
+                       ->getMock();
+               $linkFormatter->method( 'formatEntityId' )
+                       ->willReturnCallback( function( EntityId $entityId ) {
+                               $id = $entityId->getSerialization();
+                               $label = 'LABEL OF ' . $id;
+                               return "<a href='foobar/$id'>$label</a>";
+                       } );
+
                return new LexemeView(
                        TemplateFactory::getDefaultInstance(),
                        $this->newEntityTermsViewMock(),
@@ -146,7 +158,8 @@
                        $this->newSensesViewMock(),
                        $this->newStatementSectionsViewMock( 
$expectedStatements ),
                        $htmlTermRenderer,
-                       $this->newLabelDescriptionLookup()
+                       $this->newLabelDescriptionLookup(),
+                       $linkFormatter
                );
        }
 
@@ -225,7 +238,13 @@
                                htmlPiece(
                                        havingChild(
                                                both( withClass( 
'language-lexical-category-widget_language' ) )
-                                                       ->andAlso( 
havingTextContents( containsString( 'Q2' ) ) )
+                                                       ->andAlso( havingChild(
+                                                               both(
+                                                                       
tagMatchingOutline( '<a href="foobar/Q2"/>' )
+                                                               )->andAlso(
+                                                                       
havingTextContents( containsString( 'LABEL OF Q2' ) )
+                                                               )
+                                                       ) )
                                        )
                                )
                        )
@@ -257,7 +276,13 @@
                                htmlPiece(
                                        havingChild(
                                                both( withClass( 
'language-lexical-category-widget_lexical-category' ) )
-                                                       ->andAlso( 
havingTextContents( containsString( 'Q3' ) ) )
+                                                       ->andAlso( havingChild(
+                                                               both(
+                                                                       
tagMatchingOutline( '<a href="foobar/Q3"/>' )
+                                                               )->andAlso(
+                                                                       
havingTextContents( containsString( 'LABEL OF Q3' ) )
+                                                               )
+                                                       ) )
                                        )
                                )
                        )

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

Gerrit-MessageType: merged
Gerrit-Change-Id: I3825926fa02a42fb941a2d581f61246bd8268ca2
Gerrit-PatchSet: 17
Gerrit-Project: mediawiki/extensions/WikibaseLexeme
Gerrit-Branch: master
Gerrit-Owner: Jonas Kress (WMDE) <[email protected]>
Gerrit-Reviewer: Jonas Kress (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