{"version":3,"sources":["webpack://mfModules.[name]/./src/mobile.languages.structured/LanguageSearcher.js","webpack://mfModules.[name]/./src/mobile.languages.structured/mobile.languages.structured.js","webpack://mfModules.[name]/./src/mobile.languages.structured/rtlLanguages.js","webpack://mfModules.[name]/./src/mobile.languages.structured/util.js"],"names":["View","require","util","langUtil","LanguageSearcher","props","languages","getStructuredLanguages","variants","getFrequentlyUsedLanguages","deviceLanguage","call","this","extend","className","events","click a","input .search","inputPlaceholder","mw","msg","allLanguagesHeader","toLocaleUpperCase","suggestedLanguagesHeader","allLanguages","all","allLanguagesCount","length","suggestedLanguages","suggested","suggestedLanguagesCount","mfExtend","template","get","postRender","$siteLinksList","$el","find","$languageItems","$subheaders","onLinkClick","ev","lang","currentTarget","attr","saveLanguageUsageCount","onSearchInput","filterLanguages","target","val","toLowerCase","filteredList","options","forEach","language","langname","autonym","indexOf","push","variant","addClass","join","removeClass","module","exports","m","PageGateway","languageOverlay","define","deprecate","Api","log","mfUtils","rtlLanguages","getDir","dir","frequentlyUsedLanguages","hasOwn","Object","prototype","hasOwnProperty","maxFrequency","minFrequency","missingDir","self","addLangDir","parentLanguage","index","deviceLanguagesWithVariants","slice","getDeviceLanguageOrParent","keys","frequency","map","sort","a","b","toLocaleLowerCase","warn","languageMap","storage","JSON","parse","saveFrequentlyUsedLanguages","set","stringify","languageCode","count"],"mappings":"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","file":"mobile.languages.structured.js","sourcesContent":["const\n\tView = require( '../mobile.startup/View' ),\n\tutil = require( '../mobile.startup/util' ),\n\tlangUtil = require( './util' ),\n\tmfExtend = require( '../mobile.startup/mfExtend' );\n\n/**\n * Overlay displaying a structured list of languages for a page\n *\n * @class LanguageSearcher\n * @extends View\n *\n * @param {Object} props Configuration options\n * @param {Object[]} props.languages list of language objects as returned by the API\n * @param {Array|boolean} props.variants language variant objects\n *  or false if no variants exist\n * @param {string} [props.deviceLanguage] the device's primary language\n */\nfunction LanguageSearcher( props ) {\n\t/**\n\t * @prop {StructuredLanguages} languages` JSDoc.\n\t */\n\tconst languages = langUtil.getStructuredLanguages(\n\t\tprops.languages,\n\t\tprops.variants,\n\t\tlangUtil.getFrequentlyUsedLanguages(),\n\t\tprops.deviceLanguage\n\t);\n\n\tView.call(\n\t\tthis,\n\t\tutil.extend(\n\t\t\t{\n\t\t\t\tclassName: 'language-searcher',\n\t\t\t\tevents: {\n\t\t\t\t\t'click a': 'onLinkClick',\n\t\t\t\t\t'input .search': 'onSearchInput'\n\t\t\t\t},\n\t\t\t\t// the rest are template properties\n\t\t\t\tinputPlaceholder: mw.msg( 'mobile-frontend-languages-structured-overlay-search-input-placeholder' ),\n\t\t\t\t// 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\n\t\t\t\tallLanguagesHeader: mw.msg( 'mobile-frontend-languages-structured-overlay-all-languages-header' ).toLocaleUpperCase(),\n\t\t\t\tsuggestedLanguagesHeader: mw.msg( 'mobile-frontend-languages-structured-overlay-suggested-languages-header' ).toLocaleUpperCase(),\n\t\t\t\tallLanguages: languages.all,\n\t\t\t\tallLanguagesCount: languages.all.length,\n\t\t\t\tsuggestedLanguages: languages.suggested,\n\t\t\t\tsuggestedLanguagesCount: languages.suggested.length\n\t\t\t},\n\t\t\tprops\n\t\t)\n\t);\n}\n\nmfExtend( LanguageSearcher, View, {\n\t/**\n\t * @inheritdoc\n\t * @memberof LanguageSearcher\n\t * @instance\n\t */\n\ttemplate: mw.template.get( 'mobile.languages.structured', 'LanguageSearcher.hogan' ),\n\t/**\n\t * @inheritdoc\n\t * @memberof LanguageSearcher\n\t * @instance\n\t */\n\tpostRender: function () {\n\t\t// cache\n\t\tthis.$siteLinksList = this.$el.find( '.site-link-list' );\n\t\tthis.$languageItems = this.$siteLinksList.find( 'a' );\n\t\tthis.$subheaders = this.$el.find( 'h3' );\n\t},\n\t/**\n\t * Article link click event handler\n\t * @memberof LanguageSearcher\n\t * @instance\n\t * @param {jQuery.Event} ev\n\t */\n\tonLinkClick: function ( ev ) {\n\t\tconst $link = this.$el.find( ev.currentTarget ),\n\t\t\tlang = $link.attr( 'lang' );\n\n\t\tlangUtil.saveLanguageUsageCount( lang, langUtil.getFrequentlyUsedLanguages() );\n\t},\n\t/**\n\t * Search input handler\n\t * @memberof LanguageSearcher\n\t * @instance\n\t * @param {jQuery.Event} ev Event object.\n\t */\n\tonSearchInput: function ( ev ) {\n\t\tthis.filterLanguages( this.$el.find( ev.target ).val().toLowerCase() );\n\t},\n\t/**\n\t * Filter the language list to only show languages that match the current search term.\n\t * @memberof LanguageSearcher\n\t * @instance\n\t * @param {string} val of search term (lowercase).\n\t */\n\tfilterLanguages: function ( val ) {\n\t\tconst filteredList = [];\n\n\t\tif ( val ) {\n\t\t\tthis.options.languages.forEach( function ( language ) {\n\t\t\t\tconst langname = language.langname;\n\t\t\t\t// search by language code or language name\n\t\t\t\tif ( language.autonym.toLowerCase().indexOf( val ) > -1 ||\n\t\t\t\t\t\t( langname && langname.toLowerCase().indexOf( val ) > -1 ) ||\n\t\t\t\t\t\tlanguage.lang.toLowerCase().indexOf( val ) > -1\n\t\t\t\t) {\n\t\t\t\t\tfilteredList.push( language.lang );\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\tif ( this.options.variants ) {\n\t\t\t\tthis.options.variants.forEach( function ( variant ) {\n\t\t\t\t\t// search by variant code or variant name\n\t\t\t\t\tif ( variant.autonym.toLowerCase().indexOf( val ) > -1 ||\n\t\t\t\t\t\tvariant.lang.toLowerCase().indexOf( val ) > -1\n\t\t\t\t\t) {\n\t\t\t\t\t\tfilteredList.push( variant.lang );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\tthis.$languageItems.addClass( 'hidden' );\n\t\t\tif ( filteredList.length ) {\n\t\t\t\tthis.$siteLinksList.find( '.' + filteredList.join( ',.' ) ).removeClass( 'hidden' );\n\t\t\t}\n\t\t\tthis.$siteLinksList.addClass( 'filtered' );\n\t\t\tthis.$subheaders.addClass( 'hidden' );\n\t\t} else {\n\t\t\tthis.$languageItems.removeClass( 'hidden' );\n\t\t\tthis.$siteLinksList.removeClass( 'filtered' );\n\t\t\tthis.$subheaders.removeClass( 'hidden' );\n\t\t}\n\t}\n} );\n\nmodule.exports = LanguageSearcher;\n","const\n\tm = require( '../mobile.startup/moduleLoaderSingleton' ),\n\tPageGateway = require( '../mobile.startup/PageGateway' ),\n\tLanguageSearcher = require( './LanguageSearcher' ),\n\tlanguageOverlay = require( '../mobile.startup/languageOverlay/languageOverlay' );\n\n// Needed because LanguageSearcher is lazy loaded, and if we try to use require\n// (instead of m.require), webpack will excise it into mobile.common.\nm.define( 'mobile.languages.structured/LanguageSearcher', LanguageSearcher );\n\n/**\n * Temporary function for backwards compatibility with Minerva\n * which needs to be updated to use languageOverlay\n * This inefficiently allows Minerva to load the LanguageOverlay via\n * 2 identical ajax requests.\n * @ignore\n * @return {Overlay}\n */\nfunction LanguageOverlay() {\n\treturn languageOverlay( new PageGateway( new mw.Api() ) );\n}\n\n// Also can be removed after Ie6dad4bd3c80e6cfcc1d7f9ad38941a323ba3cc6 is merged\nm.deprecate( 'mobile.languages.structured/LanguageOverlay', LanguageOverlay,\n\t'mobile.startup' );\n","module.exports = [\n\t'aeb',\n\t'aeb-arab',\n\t'ar',\n\t'arc',\n\t'arq',\n\t'arz',\n\t'azb',\n\t'bcc',\n\t'bgn',\n\t'bqi',\n\t'ckb',\n\t'dv',\n\t'fa',\n\t'glk',\n\t'he',\n\t'khw',\n\t'kk-arab',\n\t'kk-cn',\n\t'ks',\n\t'ks-arab',\n\t'ku-arab',\n\t'lki',\n\t'lrc',\n\t'luz',\n\t'mzn',\n\t'pnb',\n\t'ps',\n\t'sd',\n\t'sdh',\n\t'skr',\n\t'skr-arab',\n\t'ug',\n\t'ug-arab',\n\t'ur',\n\t'yi'\n];\n","var\n\tlog = mw.log,\n\tmfUtils = require( '../mobile.startup/util' ),\n\trtlLanguages = require( './rtlLanguages' );\n\n/**\n * @typedef {Object} Language\n * @prop {string} autonym of language e.g. français\n * @prop {string} langname in the user's current language e.g French\n * @prop {string} title of the page in the language e.g. Espagne\n * @prop {string} dir (rtl or ltr)\n * @prop {string} url of the page\n *\n * @typedef {Object} SuggestedLanguage\n * @prop {string} autonym of language e.g. français\n * @prop {string} langname in the user's current language e.g French\n * @prop {string} title of the page in the language e.g. Espagne\n * @prop {string} dir (rtl or ltr)\n * @prop {string} url of the page\n * @prop {number} frequency of times the language has been used by the given user\n *\n * @typedef {Object} StructuredLanguages\n * @prop {Language[]} all languages that are available\n * @prop {SuggestedLanguage[]} suggested languages based on users browsing history\n */\n\n/**\n * Return the device language if it's in the list of article languages.\n * If the language is a variant of a general language, and if the article\n * is not available in that language, then return the general language\n * if article is available in it. For example, if the device language is\n * 'en-gb', and the article is only available in 'en', then return 'en'.\n * @param {Object[]} languages list of language objects as returned by the API\n * @param {string|undefined} deviceLanguage the device's primary language\n * @return {string|undefined} Return undefined if the article is not available in\n *  the (general or variant) device language\n */\nfunction getDeviceLanguageOrParent( languages, deviceLanguage ) {\n\tvar parentLanguage, index,\n\t\thasOwn = Object.prototype.hasOwnProperty,\n\t\tdeviceLanguagesWithVariants = {};\n\n\tif ( !deviceLanguage ) {\n\t\treturn;\n\t}\n\n\t// Are we dealing with a variant?\n\tindex = deviceLanguage.indexOf( '-' );\n\tif ( index !== -1 ) {\n\t\tparentLanguage = deviceLanguage.slice( 0, index );\n\t}\n\n\tlanguages.forEach( function ( language ) {\n\t\tif ( language.lang === parentLanguage || language.lang === deviceLanguage ) {\n\t\t\tdeviceLanguagesWithVariants[ language.lang ] = true;\n\t\t}\n\t} );\n\n\tif ( hasOwn.call( deviceLanguagesWithVariants, deviceLanguage ) ) {\n\t\t// the device language is one of the available languages\n\t\treturn deviceLanguage;\n\t} else if ( hasOwn.call( deviceLanguagesWithVariants, parentLanguage ) ) {\n\t\t// no device language, but the parent language is one of the available languages\n\t\treturn parentLanguage;\n\t}\n}\n\n/**\n * Utility function for the structured language overlay\n *\n * @class util\n * @singleton\n */\nmodule.exports = {\n\t/**\n\t * Determine whether a language is LTR or RTL\n\t * This works around T74153 and T189036\n\t * @memberof util\n\t * @instance\n\t * @param {Object} language with 'lang' key.\n\t * @return {Object} language with 'lang' key and new 'dir' key.\n\t */\n\tgetDir: function ( language ) {\n\t\tvar dir = rtlLanguages.indexOf( language.lang ) > -1 ? 'rtl' : 'ltr';\n\t\treturn mfUtils.extend( {}, language, { dir: dir } );\n\t},\n\n\t/**\n\t * Return two sets of languages: suggested and all (everything else)\n\t *\n\t * Suggested languages are the ones that the user has used before. This also\n\t * includes the user device's primary language. Suggested languages are ordered\n\t * by frequency in descending order. The device's language is always at the top.\n\t * This group also includes the variants.\n\t *\n\t * All languages are the languages that are not suggested.\n\t * Languages in this list are ordered in the lexicographical order of\n\t * their language names.\n\t * @memberof util\n\t * @instance\n\t * @param {Object[]} languages list of language objects as returned by the API\n\t * @param {Array|boolean} variants language variant objects or false if no variants exist\n\t * @param {Object} frequentlyUsedLanguages list of the frequently used languages\n\t * @param {string} [deviceLanguage] the device's primary language\n\t * @return {StructuredLanguages}\n\t */\n\tgetStructuredLanguages: function (\n\t\tlanguages, variants, frequentlyUsedLanguages, deviceLanguage\n\t) {\n\t\tvar hasOwn = Object.prototype.hasOwnProperty,\n\t\t\tmaxFrequency = 0,\n\t\t\tminFrequency = 0,\n\t\t\tmissingDir = 0,\n\t\t\tsuggestedLanguages = [],\n\t\t\tallLanguages = [],\n\t\t\tself = this;\n\n\t\t// Is the article available in the user's device language?\n\t\tdeviceLanguage = getDeviceLanguageOrParent( languages, deviceLanguage );\n\t\tif ( deviceLanguage ) {\n\t\t\tObject.keys( frequentlyUsedLanguages ).forEach( function ( language ) {\n\t\t\t\tvar frequency = frequentlyUsedLanguages[ language ];\n\t\t\t\tmaxFrequency = maxFrequency < frequency ? frequency : maxFrequency;\n\t\t\t\tminFrequency = minFrequency > frequency ? frequency : minFrequency;\n\t\t\t} );\n\n\t\t\t// Make the device language the most frequently used one so that\n\t\t\t// it appears at the top of the list when sorted by frequency.\n\t\t\tfrequentlyUsedLanguages[ deviceLanguage ] = maxFrequency + 1;\n\t\t}\n\n\t\t/**\n\t\t * @param {Object} language\n\t\t * @return {Object} which has 'dir' key.\n\t\t */\n\t\tfunction addLangDir( language ) {\n\t\t\tif ( language.dir ) {\n\t\t\t\treturn language;\n\t\t\t} else {\n\t\t\t\tmissingDir++;\n\t\t\t\treturn self.getDir( language );\n\t\t\t}\n\t\t}\n\n\t\t// Separate languages into suggested and all languages.\n\t\tlanguages.map( addLangDir ).forEach( function ( language ) {\n\t\t\tif ( hasOwn.call( frequentlyUsedLanguages, language.lang ) ) {\n\t\t\t\tlanguage.frequency = frequentlyUsedLanguages[ language.lang ];\n\t\t\t\tsuggestedLanguages.push( language );\n\t\t\t} else {\n\t\t\t\tallLanguages.push( language );\n\t\t\t}\n\t\t} );\n\n\t\t// Add variants to the suggested languages list and assign the lowest\n\t\t// frequency because the variant hasn't been clicked on yet.\n\t\t// Note that the variants data doesn't contain the article title, thus\n\t\t// we cannot show it for the variants.\n\t\tif ( variants ) {\n\t\t\tvariants.map( addLangDir ).forEach( function ( variant ) {\n\t\t\t\tif ( hasOwn.call( frequentlyUsedLanguages, variant.lang ) ) {\n\t\t\t\t\tvariant.frequency = frequentlyUsedLanguages[variant.lang];\n\t\t\t\t} else {\n\t\t\t\t\tvariant.frequency = minFrequency - 1;\n\t\t\t\t}\n\t\t\t\tsuggestedLanguages.push( variant );\n\t\t\t} );\n\t\t}\n\n\t\t// sort suggested languages in descending order by frequency\n\t\tsuggestedLanguages = suggestedLanguages.sort( function ( a, b ) {\n\t\t\treturn b.frequency - a.frequency;\n\t\t} );\n\n\t\t/**\n\t\t * Compare language names lexicographically\n\t\t *\n\t\t * @param {Object} a first language\n\t\t * @param {Object} b second language\n\t\t * @return {number} Comparison value, 1 or -1\n\t\t */\n\t\tfunction compareLanguagesByLanguageName( a, b ) {\n\t\t\treturn a.autonym.toLocaleLowerCase() < b.autonym.toLocaleLowerCase() ? -1 : 1;\n\t\t}\n\n\t\tallLanguages = allLanguages.sort( compareLanguagesByLanguageName );\n\n\t\t// This works around T74153\n\t\tlog.warn(\n\t\t\tmissingDir === 0 ? 'Direction is provided. Please remove handling in getStructuredLanguages' :\n\t\t\t\t'`dir` attribute was missing from languages. Is T74153 resolved?'\n\t\t);\n\n\t\treturn {\n\t\t\tsuggested: suggestedLanguages,\n\t\t\tall: allLanguages\n\t\t};\n\t},\n\n\t/**\n\t * Return a map of frequently used languages on the current device.\n\t * @memberof util\n\t * @instance\n\t * @return {Object}\n\t */\n\tgetFrequentlyUsedLanguages: function () {\n\t\tvar languageMap = mw.storage.get( 'langMap' );\n\n\t\treturn languageMap ? JSON.parse( languageMap ) : {};\n\t},\n\n\t/**\n\t * Save the frequently used languages to the user's device\n\t * @memberof util\n\t * @instance\n\t * @param {Object} languageMap\n\t */\n\tsaveFrequentlyUsedLanguages: function ( languageMap ) {\n\t\tmw.storage.set( 'langMap', JSON.stringify( languageMap ) );\n\t},\n\n\t/**\n\t * Increment the current language usage by one and save it to the device.\n\t * Cap the result at 100.\n\t * @memberof util\n\t * @instance\n\t * @param {string} languageCode\n\t * @param {Object} frequentlyUsedLanguages list of the frequently used languages\n\t */\n\tsaveLanguageUsageCount: function ( languageCode, frequentlyUsedLanguages ) {\n\t\tvar count = frequentlyUsedLanguages[ languageCode ] || 0;\n\n\t\tcount += 1;\n\t\t// cap at 100 as this is enough data to work on\n\t\tfrequentlyUsedLanguages[ languageCode ] = count > 100 ? 100 : count;\n\t\tthis.saveFrequentlyUsedLanguages( frequentlyUsedLanguages );\n\t}\n};\n"],"sourceRoot":""}