Bmansurov has uploaded a new change for review.

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

Change subject: Promot structured language overlay to stable
......................................................................

Promot structured language overlay to stable

Also:
* Remove the simpler language overlay.
* Rename the structured overlay to just overlay.

Bug: T129274
Change-Id: Iaecb838417fdd312dd08c4c54ba7bbdf34c3f1f7
---
M extension.json
M i18n/en.json
M i18n/qqq.json
D resources/mobile.languages.structured/LanguageOverlay.hogan
D resources/mobile.languages.structured/LanguageOverlay.js
M resources/mobile.languages/LanguageOverlay.hogan
M resources/mobile.languages/LanguageOverlay.js
R resources/mobile.languages/LanguageOverlay.less
R resources/mobile.languages/magnifying-glass.svg
R resources/mobile.languages/util.js
M resources/skins.minerva.scripts/init.js
M tests/qunit/mobile.languages.structured/test_LanguageOverlay.js
M tests/qunit/mobile.languages.structured/test_util.js
D tests/qunit/mobile.languages/test_LanguageOverlay.js
14 files changed, 200 insertions(+), 600 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/MobileFrontend 
refs/changes/29/277829/1

diff --git a/extension.json b/extension.json
index 6c8e485..3b1c898 100644
--- a/extension.json
+++ b/extension.json
@@ -1180,46 +1180,24 @@
                "mobile.languages": {
                        "class": "MFResourceLoaderParsedMessageModule",
                        "dependencies": [
-                               "mobile.overlays",
-                               "mobile.settings",
-                               "mobile.browser"
-                       ],
-                       "scripts": [
-                               "resources/mobile.languages/LanguageOverlay.js"
-                       ],
-                       "templates": {
-                               "LanguageOverlay.hogan": 
"resources/mobile.languages/LanguageOverlay.hogan"
-                       },
-                       "messages": {
-                               "0": "mobile-frontend-language-heading",
-                               "1": "mobile-frontend-language-header",
-                               "mobile-frontend-language-variant-header": [
-                                       "parse"
-                               ],
-                               "2": "mobile-frontend-language-site-choose"
-                       }
-               },
-               "mobile.languages.structured": {
-                       "class": "MFResourceLoaderParsedMessageModule",
-                       "dependencies": [
                                "mediawiki.storage",
                                "mobile.overlays"
                        ],
                        "scripts": [
-                               "resources/mobile.languages.structured/util.js",
-                               
"resources/mobile.languages.structured/LanguageOverlay.js"
+                               "resources/mobile.languages/util.js",
+                               "resources/mobile.languages/LanguageOverlay.js"
                        ],
                        "styles": [
-                               
"resources/mobile.languages.structured/LanguageOverlay.less"
+                               
"resources/mobile.languages/LanguageOverlay.less"
                        ],
                        "templates": {
-                               "LanguageOverlay.hogan": 
"resources/mobile.languages.structured/LanguageOverlay.hogan"
+                               "LanguageOverlay.hogan": 
"resources/mobile.languages/LanguageOverlay.hogan"
                        },
                        "messages": [
                                "mobile-frontend-language-heading",
-                               
"mobile-frontend-languages-structured-overlay-preferred-languages-header",
-                               
"mobile-frontend-languages-structured-overlay-all-languages-header",
-                               
"mobile-frontend-languages-structured-overlay-search-input-placeholder"
+                               
"mobile-frontend-languages-overlay-preferred-languages-header",
+                               
"mobile-frontend-languages-overlay-all-languages-header",
+                               
"mobile-frontend-languages-overlay-search-input-placeholder"
                        ]
                },
                "mobile.issues": {
@@ -1966,28 +1944,6 @@
                                "buckets": {
                                        "control": 0.97,
                                        "A": 0.03
-                               }
-                       },
-                       "@languageOverlay": "controls which language overlay 
shows in stable",
-                       "languageOverlay": {
-                               "name": "languageOverlay",
-                               "enabled": false,
-                               "buckets": {
-                                       "@control": "the ratio of users that 
see the simpler overlay",
-                                       "control": 1,
-                                       "@A": "the ratio of users that see the 
structured overlay",
-                                       "A": 0
-                               }
-                       },
-                       "@languageOverlayBeta": "controls which language 
overlay shows in beta",
-                       "languageOverlayBeta": {
-                               "name": "languageOverlayBeta",
-                               "enabled": false,
-                               "buckets": {
-                                       "@control": "the ratio of users that 
see the simpler overlay",
-                                       "control": 1,
-                                       "@A": "the ratio of users that see the 
structured overlay",
-                                       "A": 0
                                }
                        },
                        "_merge_strategy": "array_plus_2d"
diff --git a/i18n/en.json b/i18n/en.json
index 20c22c8..df35d0f 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -177,10 +177,7 @@
        "mobile-frontend-image-uploading": "'''Uploading''' image...",
        "mobile-frontend-images-status": "Images",
        "mobile-frontend-language-article-heading": "Read in another language",
-       "mobile-frontend-language-header": "This page is available in $1 
{{PLURAL:$1|language|languages}}",
        "mobile-frontend-language-heading": "<strong>Languages</strong>",
-       "mobile-frontend-language-site-choose": "Search language",
-       "mobile-frontend-language-variant-header": "Choose 
{{#language:{{CONTENTLANG}}}} variant",
        "mobile-frontend-languages-404-desc": "A valid title must be 
specified.",
        "mobile-frontend-languages-404-title": "Languages error",
        "mobile-frontend-languages-header": "Languages",
@@ -188,9 +185,9 @@
        "mobile-frontend-languages-nonexistent-title": "The page \"$1\" does 
not exist.",
        "mobile-frontend-languages-text": "$1 is available in $2 
{{PLURAL:$2|language|languages}}.",
        "mobile-frontend-languages-variant-header": 
"{{#language:{{CONTENTLANG}}}} variants",
-       
"mobile-frontend-languages-structured-overlay-preferred-languages-header": 
"Preferred languages",
-       "mobile-frontend-languages-structured-overlay-all-languages-header": 
"All languages",
-       
"mobile-frontend-languages-structured-overlay-search-input-placeholder": 
"Search for a language",
+       "mobile-frontend-languages-overlay-preferred-languages-header": 
"Preferred languages",
+       "mobile-frontend-languages-overlay-all-languages-header": "All 
languages",
+       "mobile-frontend-languages-overlay-search-input-placeholder": "Search 
for a language",
        "mobile-frontend-last-modified-date": "Last edited on $1, at $2",
        "mobile-frontend-last-modified-days": "Last edited {{PLURAL:$1|$1 
day|$1 days}} ago",
        "mobile-frontend-last-modified-hours": "Last edited {{PLURAL:$1|$1 
hour|$1 hours}} ago",
diff --git a/i18n/qqq.json b/i18n/qqq.json
index b5b999f..27524ae 100644
--- a/i18n/qqq.json
+++ b/i18n/qqq.json
@@ -175,10 +175,7 @@
        "mobile-frontend-image-uploading": "A message telling the user that an 
image is being uploaded.",
        "mobile-frontend-images-status": "On settings page label for turning 
on/off images.\n{{Identical|Image}}",
        "mobile-frontend-language-article-heading": "Button label prompting 
reader to read in another language. The button is only visible when at least 
one other language is available. Found at bottom of page.",
-       "mobile-frontend-language-header": "Header at top of language selection 
overlay describing number of languages that it is possible to read the page 
in\n* $1 - number of languages",
        "mobile-frontend-language-heading": "The title for the list of 
languages for a page.\n{{Identical|Language}}",
-       "mobile-frontend-language-site-choose": "Header for overlay when click 
on language on settings page",
-       "mobile-frontend-language-variant-header": "Header at top of language 
selection overlay prompting a user to select variant of the current 
language.\n\nSee also:\n* {{msg-mw|Mobile-frontend-languages-variant-header}}",
        "mobile-frontend-languages-404-desc": "The title for this message is 
{{msg-mw|Mobile-frontend-languages-404-title}}.",
        "mobile-frontend-languages-404-title": "Used as title for the 
description {{msg-mw|Mobile-frontend-languages-404-desc}}.",
        "mobile-frontend-languages-header": "{{Identical|Language}}",
@@ -186,9 +183,9 @@
        "mobile-frontend-languages-nonexistent-title": "Shown as error message 
on [[Special:MobileLanguages]] when the title parameter given does not map to 
an existing page.\n\nParameters:\n* $1 - page title",
        "mobile-frontend-languages-text": "Parameters:\n* $1 - page title\n* $2 
- number of languages\nSee also:\n* 
{{msg-mw|Mobile-frontend-languages-header|page title}}",
        "mobile-frontend-languages-variant-header": "See also:\n* 
{{msg-mw|Mobile-frontend-language-variant-header}}",
-       
"mobile-frontend-languages-structured-overlay-preferred-languages-header": 
"Title of the preferred languages in the structured language overlay. The text 
will be upper-cased with JS and CSS.",
-       "mobile-frontend-languages-structured-overlay-all-languages-header": 
"Title of all languages in the structured language overlay. The text will be 
upper-cased with JS and CSS.",
-       
"mobile-frontend-languages-structured-overlay-search-input-placeholder": 
"Instructional text for the language overlay search input box",
+       "mobile-frontend-languages-overlay-preferred-languages-header": "Title 
of the preferred languages in the structured language overlay. The text will be 
upper-cased with JS and CSS.",
+       "mobile-frontend-languages-overlay-all-languages-header": "Title of all 
languages in the structured language overlay. The text will be upper-cased with 
JS and CSS.",
+       "mobile-frontend-languages-overlay-search-input-placeholder": 
"Instructional text for the language overlay search input box",
        "mobile-frontend-last-modified-date": "Text that displays the date the 
page was last modified. Parameters:\n* $1 - date\n* $2 - 
time\n{{Related|Mobile-frontend-last-modified}}",
        "mobile-frontend-last-modified-days": "Text displayed on page to show 
how long ago the page was updated. Parameters:\n* $1 - number of 
days\n{{Related|Mobile-frontend-last-modified}}",
        "mobile-frontend-last-modified-hours": "Text displayed on page to show 
how long ago the page was updated. Parameters:\n* $1 - number of 
hours\n{{Related|Mobile-frontend-last-modified}}",
diff --git a/resources/mobile.languages.structured/LanguageOverlay.hogan 
b/resources/mobile.languages.structured/LanguageOverlay.hogan
deleted file mode 100644
index 3537632..0000000
--- a/resources/mobile.languages.structured/LanguageOverlay.hogan
+++ /dev/null
@@ -1,72 +0,0 @@
-<div class="panel">
-       <div class="panel-body">
-               <input type="search" class="search" 
placeholder="{{inputPlaceholder}}">
-       </div>
-</div>
-
-<div class="overlay-content-body">
-       {{#preferredLanguagesCount}}
-       <h3 class="list-header">{{preferredLanguagesHeader}}</h3>
-       <ol class="site-link-list preferred-languages">
-               {{#preferredLanguages}}
-                       <li>
-                               <a href="{{url}}" class="{{lang}}" 
hreflang="{{lang}}" lang="{{lang}}">
-                                       <div>
-                                               <span 
class="lang">{{lang}}</span>
-                                       </div>
-                                       <div>
-                                               <span 
class="langname">{{langname}}</span>
-                                               {{#title}}
-                                                       <span 
class="title">{{title}}</span>
-                                               {{/title}}
-                                       </div>
-                               </a>
-                       </li>
-               {{/preferredLanguages}}
-       </ol>
-       {{/preferredLanguagesCount}}
-
-       {{#allLanguagesCount}}
-       <h3 
class="list-header">{{allLanguagesHeader}}<span>{{allLanguagesCount}}</span></h3>
-       <ul class="site-link-list all-languages">
-               {{#allLanguages}}
-                       <li 
{{#hasVariants}}class="has-variants"{{/hasVariants}}>
-                               {{#hasVariants}}<h3 
class="list-header">{{variantsHeader}}</h3>{{/hasVariants}}
-                               {{#url}}{{! this test is important because 
variants may exist, but not the parent language }}
-                               <a href="{{url}}" class="{{lang}}" 
hreflang="{{lang}}" lang="{{lang}}">
-                                       <div>
-                                               <span 
class="lang">{{lang}}</span>
-                                       </div>
-                                       <div>
-                                               <span 
class="langname">{{langname}}</span>
-                                               {{#title}}
-                                                       <span 
class="title">{{title}}</span>
-                                               {{/title}}
-                                       </div>
-                               </a>
-                               {{/url}}
-                               {{#hasVariants}}
-                                       <ul class="variants">
-                                       {{#variants}}
-                                               <li>
-                                                       <a href="{{url}}" 
class="{{lang}}" hreflang="{{lang}}" lang="{{lang}}">
-                                                               <div>
-                                                                       <span 
class="lang">{{lang}}</span>
-                                                                       <span 
class="variant">{{variant}}</span>
-                                                               </div>
-                                                               <div>
-                                                                       <span 
class="langname">{{langname}}</span>
-                                                                       
{{#title}}
-                                                                               
<span class="title">{{title}}</span>
-                                                                       
{{/title}}
-                                                               </div>
-                                                       </a>
-                                               </li>
-                                       {{/variants}}
-                                       </ul>
-                               {{/hasVariants}}
-                       </li>
-               {{/allLanguages}}
-       </ul>
-       {{/allLanguagesCount}}
-</div>
diff --git a/resources/mobile.languages.structured/LanguageOverlay.js 
b/resources/mobile.languages.structured/LanguageOverlay.js
deleted file mode 100644
index df86106..0000000
--- a/resources/mobile.languages.structured/LanguageOverlay.js
+++ /dev/null
@@ -1,163 +0,0 @@
-( function ( M, $ ) {
-
-       var Overlay = M.require( 'mobile.overlays/Overlay' ),
-               util = M.require( 'mobile.languages.structured/util' );
-
-       /**
-        * Overlay displaying a structured list of languages for a page
-        *
-        * @class LanguageOverlay
-        * @extends Overlay
-        */
-       function LanguageOverlay( options ) {
-               var languages;
-
-               if ( options.languages && options.languages.length ) {
-                       languages = util.getStructuredLanguages( 
options.languages, util.getFrequentlyUsedLanguages(), options.deviceLanguage );
-                       options.allLanguages = languages.all;
-                       options.allLanguagesCount = languages.all.length;
-                       options.preferredLanguages = languages.preferred;
-                       options.preferredLanguagesCount = 
languages.preferred.length;
-               }
-
-               Overlay.call( this, options );
-       }
-
-       OO.mfExtend( LanguageOverlay, Overlay, {
-               /** @inheritdoc */
-               className: Overlay.prototype.className + ' language-overlay',
-               defaults: $.extend( {}, Overlay.prototype.defaults, {
-                       heading: mw.msg( 'mobile-frontend-language-heading' ),
-                       inputPlaceholder: mw.msg( 
'mobile-frontend-languages-structured-overlay-search-input-placeholder' ),
-                       // we can't rely on CSS only to uppercase the headings. 
See 
https://stackoverflow.com/questions/3777443/css-text-transform-not-working-properly-for-turkish-characters
-                       allLanguagesHeader: mw.msg( 
'mobile-frontend-languages-structured-overlay-all-languages-header' 
).toLocaleUpperCase(),
-                       preferredLanguagesHeader: mw.msg( 
'mobile-frontend-languages-structured-overlay-preferred-languages-header' 
).toLocaleUpperCase()
-               } ),
-               /** @inheritdoc */
-               templatePartials: $.extend( {}, 
Overlay.prototype.templatePartials, {
-                       content: mw.template.get( 
'mobile.languages.structured', 'LanguageOverlay.hogan' )
-               } ),
-               /** @inheritdoc */
-               events: $.extend( {}, Overlay.prototype.events, {
-                       'click a': 'onLinkClick',
-                       'input .search': 'onSearchInput'
-               } ),
-               /** @inheritdoc */
-               postRender: function () {
-                       Overlay.prototype.postRender.apply( this );
-
-                       // cache
-                       this.$searchInput = this.$( 'input.search' );
-                       this.$siteLinksList = this.$( '.site-link-list' );
-                       this.$languageItems = this.$siteLinksList.find( 'a' );
-                       this.$subheaders = this.$( 'h3' );
-
-                       if ( this.options.languageSwitcherSchema ) {
-                               this.options.languageSwitcherSchema.log( {
-                                       event: 'languageListLoaded',
-                                       languageOverlayVersion: 
'structured-overlay',
-                                       languageCount: 
this.$languageItems.length
-                               } );
-                       }
-               },
-               /** @inheritdoc */
-               onExit: function () {
-                       if ( this.options.languageSwitcherSchema ) {
-                               this.options.languageSwitcherSchema.log( {
-                                       event: 'exitModal',
-                                       exitModal: 'dismissed',
-                                       searchInputHasQuery: 
this.$searchInput.val().length > 0,
-                                       languageCount: 
this.$siteLinksList.children( ':visible' ).length
-                               } );
-                               // stop logging when the user decides to close 
the modal
-                               this.options.languageSwitcherSchema.stopLogging 
= true;
-                       }
-
-                       Overlay.prototype.onExit.apply( this, arguments );
-               },
-               /**
-                * Article link click event handler
-                * @param {jQuery.Event} ev
-                */
-               onLinkClick: function ( ev ) {
-                       var $link = this.$( ev.currentTarget ),
-                               lang = $link.attr( 'lang' ),
-                               searchInputHasQuery = 
this.$searchInput.val().length > 0,
-                               $visibleListItems = 
this.$siteLinksList.children( ':visible' ),
-                               index;
-
-                       util.saveLanguageUsageCount( lang, 
util.getFrequentlyUsedLanguages() );
-
-                       // find the index of the clicked language in the list 
of visible results
-                       $.each( $visibleListItems, function ( i, item ) {
-                               index = i + 1;
-                               if ( $( item ).hasClass( lang ) ) {
-                                       return false;
-                               }
-                       } );
-
-                       if ( this.options.languageSwitcherSchema ) {
-                               this.options.languageSwitcherSchema.log( {
-                                       event: 'exitModal',
-                                       exitModal: 'tapped-on-result',
-                                       languageTapped: lang,
-                                       positionOfLanguageTapped: index,
-                                       searchInputHasQuery: 
searchInputHasQuery,
-                                       languageCount: $visibleListItems.length
-                               } );
-                       }
-               },
-
-               /**
-                * Search input handler
-                * @param {jQuery.Event} ev Event object.
-                */
-               onSearchInput: function ( ev ) {
-                       this.filterLanguages( $( ev.target 
).val().toLowerCase() );
-
-                       // log when the first search character is entered
-                       if ( this.options.languageSwitcherSchema ) {
-                               if ( !this.hasFirstSearchBeenLogged ) {
-                                       
this.options.languageSwitcherSchema.log( {
-                                               event: 'startLanguageSearch'
-                                       } );
-                                       this.hasFirstSearchBeenLogged = true;
-                               }
-                       }
-               },
-
-               /**
-                * Filter the language list to only show languages that match 
the current search term.
-                *
-                * @param {String} val of search term (lowercase).
-                */
-               filterLanguages: function ( val ) {
-                       var filteredList = [];
-
-                       if ( val && this.options.languages ) {
-                               $.each( this.options.languages, function ( i, 
language ) {
-                                       // search by language code or language 
name
-                                       if ( 
language.langname.toLowerCase().indexOf( val ) > -1 ||
-                                                       
language.lang.toLowerCase().indexOf( val ) > -1
-                                       ) {
-                                               filteredList.push( 
language.lang );
-                                       }
-                               } );
-
-                               this.$languageItems.addClass( 'hidden' );
-                               if ( filteredList.length ) {
-                                       this.$siteLinksList.find( '.' + 
filteredList.join( ',.' ) ).removeClass( 'hidden' );
-                               }
-                               this.$siteLinksList.addClass( 'filtered' );
-                               this.$subheaders.addClass( 'hidden' );
-                       } else {
-                               this.$languageItems.removeClass( 'hidden' );
-                               this.$siteLinksList.removeClass( 'filtered' );
-                               this.$subheaders.removeClass( 'hidden' );
-                       }
-               }
-       } );
-
-       M.define( 'mobile.languages.structured/LanguageOverlay', 
LanguageOverlay );
-
-}( mw.mobileFrontend, jQuery ) );
diff --git a/resources/mobile.languages/LanguageOverlay.hogan 
b/resources/mobile.languages/LanguageOverlay.hogan
index bcc4e05..3537632 100644
--- a/resources/mobile.languages/LanguageOverlay.hogan
+++ b/resources/mobile.languages/LanguageOverlay.hogan
@@ -1,25 +1,72 @@
 <div class="panel">
-       <input type="search" class="search" placeholder="{{placeholder}}">
+       <div class="panel-body">
+               <input type="search" class="search" 
placeholder="{{inputPlaceholder}}">
+       </div>
 </div>
-{{#variantHeader}}
-<h3 class="list-header">{{{variantHeader}}}</h3>
-<ul class="site-link-list">
-       {{#variants}}
-               <li>
-                       <a href="{{url}}" hreflang="{{lang}}" 
lang="{{lang}}">{{langname}}</a>
-               </li>
-       {{/variants}}
-</ul>
-{{/variantHeader}}
-{{#header}}
-{{#variantHeader}}
-<h3 class="list-header">{{{header}}}</h3>
-{{/variantHeader}}
-<ul class="site-link-list">
-       {{#languages}}
-               <li>
-                       <a href="{{url}}" hreflang="{{lang}}" 
lang="{{lang}}"><span>{{langname}}</span>{{#title}} | {{title}}{{/title}}</a>
-               </li>
-       {{/languages}}
-</ul>
-{{/header}}
+
+<div class="overlay-content-body">
+       {{#preferredLanguagesCount}}
+       <h3 class="list-header">{{preferredLanguagesHeader}}</h3>
+       <ol class="site-link-list preferred-languages">
+               {{#preferredLanguages}}
+                       <li>
+                               <a href="{{url}}" class="{{lang}}" 
hreflang="{{lang}}" lang="{{lang}}">
+                                       <div>
+                                               <span 
class="lang">{{lang}}</span>
+                                       </div>
+                                       <div>
+                                               <span 
class="langname">{{langname}}</span>
+                                               {{#title}}
+                                                       <span 
class="title">{{title}}</span>
+                                               {{/title}}
+                                       </div>
+                               </a>
+                       </li>
+               {{/preferredLanguages}}
+       </ol>
+       {{/preferredLanguagesCount}}
+
+       {{#allLanguagesCount}}
+       <h3 
class="list-header">{{allLanguagesHeader}}<span>{{allLanguagesCount}}</span></h3>
+       <ul class="site-link-list all-languages">
+               {{#allLanguages}}
+                       <li 
{{#hasVariants}}class="has-variants"{{/hasVariants}}>
+                               {{#hasVariants}}<h3 
class="list-header">{{variantsHeader}}</h3>{{/hasVariants}}
+                               {{#url}}{{! this test is important because 
variants may exist, but not the parent language }}
+                               <a href="{{url}}" class="{{lang}}" 
hreflang="{{lang}}" lang="{{lang}}">
+                                       <div>
+                                               <span 
class="lang">{{lang}}</span>
+                                       </div>
+                                       <div>
+                                               <span 
class="langname">{{langname}}</span>
+                                               {{#title}}
+                                                       <span 
class="title">{{title}}</span>
+                                               {{/title}}
+                                       </div>
+                               </a>
+                               {{/url}}
+                               {{#hasVariants}}
+                                       <ul class="variants">
+                                       {{#variants}}
+                                               <li>
+                                                       <a href="{{url}}" 
class="{{lang}}" hreflang="{{lang}}" lang="{{lang}}">
+                                                               <div>
+                                                                       <span 
class="lang">{{lang}}</span>
+                                                                       <span 
class="variant">{{variant}}</span>
+                                                               </div>
+                                                               <div>
+                                                                       <span 
class="langname">{{langname}}</span>
+                                                                       
{{#title}}
+                                                                               
<span class="title">{{title}}</span>
+                                                                       
{{/title}}
+                                                               </div>
+                                                       </a>
+                                               </li>
+                                       {{/variants}}
+                                       </ul>
+                               {{/hasVariants}}
+                       </li>
+               {{/allLanguages}}
+       </ul>
+       {{/allLanguagesCount}}
+</div>
diff --git a/resources/mobile.languages/LanguageOverlay.js 
b/resources/mobile.languages/LanguageOverlay.js
index 376a1e8..c5b0856 100644
--- a/resources/mobile.languages/LanguageOverlay.js
+++ b/resources/mobile.languages/LanguageOverlay.js
@@ -1,161 +1,111 @@
 ( function ( M, $ ) {
 
        var Overlay = M.require( 'mobile.overlays/Overlay' ),
-               settings = M.require( 'mobile.settings/settings' );
+               util = M.require( 'mobile.languages/util' );
 
        /**
-        * Overlay displaying list of languages for a page
+        * Overlay displaying a structured list of languages for a page
+        *
         * @class LanguageOverlay
         * @extends Overlay
         */
        function LanguageOverlay( options ) {
-               var langMap;
+               var languages;
 
                if ( options.languages && options.languages.length ) {
-                       options.header = mw.msg( 
'mobile-frontend-language-header', options.languages.length );
+                       languages = util.getStructuredLanguages( 
options.languages, util.getFrequentlyUsedLanguages(), options.deviceLanguage );
+                       options.allLanguages = languages.all;
+                       options.allLanguagesCount = languages.all.length;
+                       options.preferredLanguages = languages.preferred;
+                       options.preferredLanguagesCount = 
languages.preferred.length;
                }
-               if ( options.variants && options.variants.length ) {
-                       options.variantHeader = mw.msg( 
'mobile-frontend-language-variant-header' );
-               }
-               langMap = settings.get( 'langMap' );
-               this.languageMap = langMap ? $.parseJSON( langMap ) : {};
-               if ( options.currentLanguage ) {
-                       this.trackLanguage( options.currentLanguage );
-               }
-               options = this._sortLanguages( options );
-               Overlay.apply( this, arguments );
+
+               Overlay.call( this, options );
        }
 
        OO.mfExtend( LanguageOverlay, Overlay, {
-               /**
-                * @inheritdoc
-                * @cfg {Object} defaults Default options hash.
-                * @cfg {String} defaults.heading The title for the list of 
languages for a page.
-                * @cfg {String} defaults.placeholder Placeholder text for the 
search input.
-                * @cfg {Object} defaults.languages a list of languages with 
keys {langname, lang, title, url}
-                */
+               /** @inheritdoc */
+               className: Overlay.prototype.className + ' language-overlay',
                defaults: $.extend( {}, Overlay.prototype.defaults, {
                        heading: mw.msg( 'mobile-frontend-language-heading' ),
-                       placeholder: mw.msg( 
'mobile-frontend-language-site-choose' )
+                       inputPlaceholder: mw.msg( 
'mobile-frontend-languages-overlay-search-input-placeholder' ),
+                       // we can't rely on CSS only to uppercase the headings. 
See 
https://stackoverflow.com/questions/3777443/css-text-transform-not-working-properly-for-turkish-characters
+                       allLanguagesHeader: mw.msg( 
'mobile-frontend-languages-overlay-all-languages-header' ).toLocaleUpperCase(),
+                       preferredLanguagesHeader: mw.msg( 
'mobile-frontend-languages-overlay-preferred-languages-header' 
).toLocaleUpperCase()
                } ),
-               /**
-                * @inheritdoc
-                */
-               className: 'language-overlay overlay',
-               /**
-                * @inheritdoc
-                */
+               /** @inheritdoc */
                templatePartials: $.extend( {}, 
Overlay.prototype.templatePartials, {
                        content: mw.template.get( 'mobile.languages', 
'LanguageOverlay.hogan' )
                } ),
-               /**
-                * @inheritdoc
-                */
+               /** @inheritdoc */
                events: $.extend( {}, Overlay.prototype.events, {
-                       'click ul a': 'onLinkClick',
+                       'click a': 'onLinkClick',
                        'input .search': 'onSearchInput'
                } ),
                /** @inheritdoc */
                postRender: function () {
                        Overlay.prototype.postRender.apply( this );
-                       this.options.languageSwitcherSchema.log( {
-                               event: 'languageListLoaded',
-                               languageOverlayVersion: 'simpler-overlay',
-                               languageCount: this.$( '.site-link-list li' 
).length
-                       } );
+
+                       // cache
+                       this.$searchInput = this.$( 'input.search' );
+                       this.$siteLinksList = this.$( '.site-link-list' );
+                       this.$languageItems = this.$siteLinksList.find( 'a' );
+                       this.$subheaders = this.$( 'h3' );
+
+                       if ( this.options.languageSwitcherSchema ) {
+                               this.options.languageSwitcherSchema.log( {
+                                       event: 'languageListLoaded',
+                                       languageOverlayVersion: 
'structured-overlay',
+                                       languageCount: 
this.$languageItems.length
+                               } );
+                       }
                },
                /** @inheritdoc */
                onExit: function () {
-                       this.options.languageSwitcherSchema.log( {
-                               event: 'exitModal',
-                               exitModal: 'dismissed',
-                               searchInputHasQuery: this.$( 'input.search' 
).val().length > 0,
-                               languageCount: this.$( '.site-link-list' 
).children( ':visible' ).length
-                       } );
-                       // stop logging when the user decides to close the modal
-                       this.options.languageSwitcherSchema.stopLogging = true;
+                       if ( this.options.languageSwitcherSchema ) {
+                               this.options.languageSwitcherSchema.log( {
+                                       event: 'exitModal',
+                                       exitModal: 'dismissed',
+                                       searchInputHasQuery: 
this.$searchInput.val().length > 0,
+                                       languageCount: 
this.$siteLinksList.children( ':visible' ).length
+                               } );
+                               // stop logging when the user decides to close 
the modal
+                               this.options.languageSwitcherSchema.stopLogging 
= true;
+                       }
+
                        Overlay.prototype.onExit.apply( this, arguments );
                },
                /**
-                * Sorts the provided languages based on previous usage and 
tags them
-                * with a property preferred for template usage
-                * @private
-                * @param {Object} options
-                */
-               _sortLanguages: function ( options ) {
-                       var langMap = this.languageMap;
-                       options.languages = options.languages.sort( function ( 
a, b ) {
-                               var x = langMap[ a.lang ] || 0,
-                                       y = langMap[ b.lang ] || 0;
-                               if ( x === y ) {
-                                       return a.langname < b.langname ? -1 : 1;
-                               } else {
-                                       return x > y ? -1 : 1;
-                               }
-                       } );
-                       return options;
-               },
-               /**
-                * Track locally the language of the user for future renders.
-                * @param {String} languageCode to track
-                */
-               trackLanguage: function ( languageCode ) {
-                       var count,
-                               langMap = this.languageMap || {};
-
-                       if ( langMap ) {
-                               count = langMap[ languageCode ] || 0;
-                               count += 1;
-                               // cap at 100 as this is enough data to work on
-                               langMap[ languageCode ] = count > 100 ? 100 : 
count;
-                       }
-
-                       this.languageMap = langMap;
-                       // Attempt to store the map. mw.storage might fail but 
it's not essential so we don't care.
-                       settings.save( 'langMap', JSON.stringify( langMap ) );
-               },
-
-               /**
-                * Filter the language list to only show languages that match 
the current search term.
-                * @param {String} val of search term (lowercase).
-                */
-               filterLists: function ( val ) {
-                       var $items = this.$( '.site-link-list li' ),
-                               $subheaders = this.$( 'h3' );
-
-                       if ( val ) {
-                               $subheaders.hide();
-                               $items.each( function () {
-                                       var $item = $( this );
-                                       if ( $item.find( 'span' 
).text().toLowerCase().indexOf( val ) > -1 ) {
-                                               $item.show();
-                                       } else {
-                                               $item.hide();
-                                       }
-                               } );
-                       } else {
-                               $subheaders.show();
-                               $items.show();
-                       }
-               },
-
-               /**
-                * Language link click handler
-                * @param {jQuery.Event} ev Event object.
+                * Article link click event handler
+                * @param {jQuery.Event} ev
                 */
                onLinkClick: function ( ev ) {
                        var $link = this.$( ev.currentTarget ),
-                               lang = $link.attr( 'lang' );
+                               lang = $link.attr( 'lang' ),
+                               searchInputHasQuery = 
this.$searchInput.val().length > 0,
+                               $visibleListItems = 
this.$siteLinksList.children( ':visible' ),
+                               index;
 
-                       this.options.languageSwitcherSchema.log( {
-                               event: 'exitModal',
-                               exitModal: 'tapped-on-result',
-                               languageTapped: lang,
-                               positionOfLanguageTapped: $link.parents( 'li' 
).index() + 1,
-                               searchInputHasQuery: this.$( 'input.search' 
).val().length > 0,
-                               languageCount: this.$( '.site-link-list' 
).children( ':visible' ).length
+                       util.saveLanguageUsageCount( lang, 
util.getFrequentlyUsedLanguages() );
+
+                       // find the index of the clicked language in the list 
of visible results
+                       $.each( $visibleListItems, function ( i, item ) {
+                               index = i + 1;
+                               if ( $( item ).hasClass( lang ) ) {
+                                       return false;
+                               }
                        } );
-                       this.trackLanguage( lang );
+
+                       if ( this.options.languageSwitcherSchema ) {
+                               this.options.languageSwitcherSchema.log( {
+                                       event: 'exitModal',
+                                       exitModal: 'tapped-on-result',
+                                       languageTapped: lang,
+                                       positionOfLanguageTapped: index,
+                                       searchInputHasQuery: 
searchInputHasQuery,
+                                       languageCount: $visibleListItems.length
+                               } );
+                       }
                },
 
                /**
@@ -163,14 +113,48 @@
                 * @param {jQuery.Event} ev Event object.
                 */
                onSearchInput: function ( ev ) {
+                       this.filterLanguages( $( ev.target 
).val().toLowerCase() );
+
                        // log when the first search character is entered
-                       if ( !this.hasFirstSearchBeenLogged ) {
-                               this.options.languageSwitcherSchema.log( {
-                                       event: 'startLanguageSearch'
-                               } );
-                               this.hasFirstSearchBeenLogged = true;
+                       if ( this.options.languageSwitcherSchema ) {
+                               if ( !this.hasFirstSearchBeenLogged ) {
+                                       
this.options.languageSwitcherSchema.log( {
+                                               event: 'startLanguageSearch'
+                                       } );
+                                       this.hasFirstSearchBeenLogged = true;
+                               }
                        }
-                       this.filterLists( $( ev.target ).val().toLowerCase() );
+               },
+
+               /**
+                * Filter the language list to only show languages that match 
the current search term.
+                *
+                * @param {String} val of search term (lowercase).
+                */
+               filterLanguages: function ( val ) {
+                       var filteredList = [];
+
+                       if ( val && this.options.languages ) {
+                               $.each( this.options.languages, function ( i, 
language ) {
+                                       // search by language code or language 
name
+                                       if ( 
language.langname.toLowerCase().indexOf( val ) > -1 ||
+                                                       
language.lang.toLowerCase().indexOf( val ) > -1
+                                       ) {
+                                               filteredList.push( 
language.lang );
+                                       }
+                               } );
+
+                               this.$languageItems.addClass( 'hidden' );
+                               if ( filteredList.length ) {
+                                       this.$siteLinksList.find( '.' + 
filteredList.join( ',.' ) ).removeClass( 'hidden' );
+                               }
+                               this.$siteLinksList.addClass( 'filtered' );
+                               this.$subheaders.addClass( 'hidden' );
+                       } else {
+                               this.$languageItems.removeClass( 'hidden' );
+                               this.$siteLinksList.removeClass( 'filtered' );
+                               this.$subheaders.removeClass( 'hidden' );
+                       }
                }
        } );
 
diff --git a/resources/mobile.languages.structured/LanguageOverlay.less 
b/resources/mobile.languages/LanguageOverlay.less
similarity index 100%
rename from resources/mobile.languages.structured/LanguageOverlay.less
rename to resources/mobile.languages/LanguageOverlay.less
diff --git a/resources/mobile.languages.structured/magnifying-glass.svg 
b/resources/mobile.languages/magnifying-glass.svg
similarity index 100%
rename from resources/mobile.languages.structured/magnifying-glass.svg
rename to resources/mobile.languages/magnifying-glass.svg
diff --git a/resources/mobile.languages.structured/util.js 
b/resources/mobile.languages/util.js
similarity index 98%
rename from resources/mobile.languages.structured/util.js
rename to resources/mobile.languages/util.js
index c61bb1f..839e98d 100644
--- a/resources/mobile.languages.structured/util.js
+++ b/resources/mobile.languages/util.js
@@ -203,6 +203,6 @@
                util.saveFrequentlyUsedLanguages( frequentlyUsedLanguages );
        };
 
-       M.define( 'mobile.languages.structured/util', util );
+       M.define( 'mobile.languages/util', util );
 
 }( mw.mobileFrontend, jQuery ) );
diff --git a/resources/skins.minerva.scripts/init.js 
b/resources/skins.minerva.scripts/init.js
index 2b6136e..3f220b6 100644
--- a/resources/skins.minerva.scripts/init.js
+++ b/resources/skins.minerva.scripts/init.js
@@ -182,20 +182,12 @@
        // Routes
        overlayManager.add( /^\/media\/(.+)$/, loadImageOverlay );
        overlayManager.add( /^\/languages$/, function () {
-               var result = $.Deferred(),
-                       languageOverlayExperiment = context.isBetaGroupMember() 
? experiments.languageOverlayBeta : experiments.languageOverlay,
-                       languageOverlayModule = 'mobile.languages';
+               var result = $.Deferred();
 
-               if ( languageOverlayExperiment &&
-                       mw.experiments.getBucket( languageOverlayExperiment, 
mw.user.sessionId() ) === 'A'
-               ) {
-                       languageOverlayModule = 'mobile.languages.structured';
-               }
-
-               loader.loadModule( languageOverlayModule, true ).done( function 
( loadingOverlay ) {
+               loader.loadModule( 'mobile.languages', true ).done( function ( 
loadingOverlay ) {
                        var PageGateway = M.require( 
'mobile.startup/PageGateway' ),
                                gateway = new PageGateway( new mw.Api() ),
-                               LanguageOverlay = M.require( 
languageOverlayModule + '/LanguageOverlay' );
+                               LanguageOverlay = M.require( 
'mobile.languages/LanguageOverlay' );
 
                        gateway.getPageLanguages( mw.config.get( 'wgPageName' ) 
).done( function ( data ) {
                                loadingOverlay.hide();
diff --git a/tests/qunit/mobile.languages.structured/test_LanguageOverlay.js 
b/tests/qunit/mobile.languages.structured/test_LanguageOverlay.js
index 6f1c648..ec981fb 100644
--- a/tests/qunit/mobile.languages.structured/test_LanguageOverlay.js
+++ b/tests/qunit/mobile.languages.structured/test_LanguageOverlay.js
@@ -1,5 +1,5 @@
 ( function ( M ) {
-       var LanguageOverlay = M.require( 
'mobile.languages.structured/LanguageOverlay' ),
+       var LanguageOverlay = M.require( 'mobile.languages/LanguageOverlay' ),
                apiLanguages = [
                        {
                                lang: 'ar',
diff --git a/tests/qunit/mobile.languages.structured/test_util.js 
b/tests/qunit/mobile.languages.structured/test_util.js
index dd1239b..e9be600 100644
--- a/tests/qunit/mobile.languages.structured/test_util.js
+++ b/tests/qunit/mobile.languages.structured/test_util.js
@@ -1,7 +1,7 @@
 ( function ( M ) {
-       var util = M.require( 'mobile.languages.structured/util' );
+       var util = M.require( 'mobile.languages/util' );
 
-       QUnit.module( 'MobileFrontend: Structured LanguageOverlay', {
+       QUnit.module( 'MobileFrontend: LanguageOverlay', {
                setup: function () {
                        if ( mw.eventLog ) {
                                this.sandbox.stub( 
mw.eventLog.Schema.prototype, 'log' );
diff --git a/tests/qunit/mobile.languages/test_LanguageOverlay.js 
b/tests/qunit/mobile.languages/test_LanguageOverlay.js
deleted file mode 100644
index 3e8bf29..0000000
--- a/tests/qunit/mobile.languages/test_LanguageOverlay.js
+++ /dev/null
@@ -1,138 +0,0 @@
-( function ( M, LanguageOverlay ) {
-       var settings = M.require( 'mobile.settings/settings' ),
-               schemaMobileWebLanguageSwitcher = M.require(
-                       'mobile.loggingSchemas/schemaMobileWebLanguageSwitcher' 
);
-
-       QUnit.module( 'MobileFrontend: LanguageOverlay', {
-               setup: function () {
-                       this.sandbox.stub( settings, 'get' ).withArgs( 
'langMap' )
-                               .returns( '{}' );
-                       if ( mw.eventLog ) {
-                               this.sandbox.stub( 
mw.eventLog.Schema.prototype, 'log' );
-                       }
-               }
-       } );
-
-       QUnit.test( 'filterLanguages', 2, function ( assert ) {
-               var overlay = new LanguageOverlay( {
-                       languageSwitcherSchema: schemaMobileWebLanguageSwitcher,
-                       languages: [
-                               {
-                                       lang: 'en',
-                                       langname: 'English',
-                                       title: 'The dog',
-                                       url: 'wiki/Dog'
-                               },
-                               {
-                                       lang: 'fr',
-                                       langname: 'French',
-                                       title: 'Le chien',
-                                       url: 'wiki/chien'
-                               },
-                               {
-                                       lang: 'pt',
-                                       langname: 'Portuguese',
-                                       title: 'O cachorro',
-                                       url: 'wiki/cachorro'
-                               }
-                       ]
-               } );
-               // Needed so we can make use of :visible
-               overlay.show();
-               overlay.filterLists( 'port' );
-               assert.ok( overlay.$( '.site-link-list li' ).eq( 1 ).css( 
'display' ) === 'none', 'French should be hidden.' );
-               assert.ok( overlay.$( '.site-link-list li' ).eq( 2 ).css( 
'display' ) !== 'none', 'Portuguese should be visible.' );
-               overlay.hide();
-       } );
-
-       QUnit.test( 'Preferred Languages', 3, function ( assert ) {
-               var overlay = new LanguageOverlay( {
-                               languageSwitcherSchema: 
schemaMobileWebLanguageSwitcher,
-                               languages: [],
-                               currentLanguage: 'en'
-                       } );
-               overlay.trackLanguage( 'de' );
-               overlay.trackLanguage( 'fr' );
-               overlay.trackLanguage( 'fr' );
-               assert.strictEqual( overlay.languageMap.en, 1, 'Current 
language automatically tracked.' );
-               assert.strictEqual( overlay.languageMap.de, 1, 'Saved click on 
language link' );
-               assert.strictEqual( overlay.languageMap.fr, 2, 'Saved click on 
language link' );
-       } );
-
-       QUnit.module( 'MobileFrontend: LanguageOverlay##_sortLanguages', {
-               setup: function () {
-                       this.sandbox.stub( settings, 'get' ).withArgs( 
'langMap' )
-                               .returns( '{ "es": 3, "za": 100, "fr": 50 }' );
-                       if ( mw.eventLog ) {
-                               this.sandbox.stub( 
mw.eventLog.Schema.prototype, 'log' );
-                       }
-               }
-       } );
-
-       QUnit.test( 'Languages get sorted by order', 2, function ( assert ) {
-               var languages,
-                       overlay = new LanguageOverlay( {
-                               languageSwitcherSchema: 
schemaMobileWebLanguageSwitcher,
-                               languages: [
-                                       {
-                                               lang: 'es'
-                                       },
-                                       {
-                                               lang: 'za'
-                                       },
-                                       {
-                                               lang: 'fr'
-                                       }
-                               ]
-                       } );
-               languages = overlay.options.languages;
-               assert.strictEqual( languages[0].lang, 'za', 'Language with 
highest score appears at top' );
-               assert.strictEqual( languages[2].lang, 'es', 'Language with 
lowest score at bottom' );
-       } );
-
-       QUnit.test( 'Languages get sorted by order (different scripts)', 7, 
function ( assert ) {
-               var languages,
-                       overlay = new LanguageOverlay( {
-                               languageSwitcherSchema: 
schemaMobileWebLanguageSwitcher,
-                               languages: [
-                                       {
-                                               langname: 'French',
-                                               lang: 'fr'
-                                       },
-                                       {
-                                               langname: 'العربية',
-                                               lang: 'ar'
-                                       },
-                                       {
-                                               langname: 'oʻzbekcha/ўзбекча',
-                                               lang: 'uz'
-                                       },
-                                       {
-                                               langname: 'English',
-                                               lang: 'en'
-                                       },
-                                       {
-                                               langname: 'Deutsch',
-                                               lang: 'de'
-                                       },
-                                       {
-                                               langname: '한국어',
-                                               lang: 'ko'
-                                       },
-                                       {
-                                               langname: 'русский',
-                                               lang: 'ru'
-                                       }
-                               ]
-                       } );
-               languages = overlay.options.languages;
-               assert.strictEqual( languages[0].lang, 'fr', 'Language with 
highest score appears at top' );
-               assert.strictEqual( languages[1].lang, 'de', 'Alphabetical 
order #1' );
-               assert.strictEqual( languages[2].lang, 'en', 'Alphabetical 
order #2' );
-               assert.strictEqual( languages[3].lang, 'uz', 'Alphabetical 
order #3' );
-               assert.strictEqual( languages[4].lang, 'ru', 'Alphabetical 
order #4' );
-               assert.strictEqual( languages[5].lang, 'ar', 'Alphabetical 
order #5' );
-               assert.strictEqual( languages[6].lang, 'ko', 'Alphabetical 
order #6' );
-       } );
-
-} )( mw.mobileFrontend, mw.mobileFrontend.require( 
'mobile.languages/LanguageOverlay' ) );

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: Iaecb838417fdd312dd08c4c54ba7bbdf34c3f1f7
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/MobileFrontend
Gerrit-Branch: master
Gerrit-Owner: Bmansurov <[email protected]>

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

Reply via email to