{"version":3,"file":"mobile.startup.js","mappings":"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","sources":["webpack://mfModules/./src/mobile.startup/LanguageInfo.js","webpack://mfModules/./src/mobile.startup/MessageBox.js","webpack://mfModules/./src/mobile.startup/Section.js","webpack://mfModules/./src/mobile.startup/languageOverlay/getDeviceLanguage.js","webpack://mfModules/./src/mobile.startup/languageOverlay/languageInfoOverlay.js","webpack://mfModules/./src/mobile.startup/languageOverlay/languageOverlay.js","webpack://mfModules/./src/mobile.startup/mediaViewer/overlay.js","webpack://mfModules/./src/mobile.startup/mobile.startup.js","webpack://mfModules/./src/mobile.startup/promisedView.js","webpack://mfModules/./src/mobile.startup/references/ReferencesGateway.js","webpack://mfModules/./src/mobile.startup/references/ReferencesHtmlScraperGateway.js","webpack://mfModules/./src/mobile.startup/references/references.js","webpack://mfModules/./src/mobile.startup/search/SearchGateway.js","webpack://mfModules/./src/mobile.startup/search/SearchHeaderView.js","webpack://mfModules/./src/mobile.startup/search/SearchOverlay.js","webpack://mfModules/./src/mobile.startup/search/SearchResultsView.js","webpack://mfModules/./src/mobile.startup/search/searchHeader.js","webpack://mfModules/./src/mobile.startup/time.js"],"sourcesContent":["const util = require( './util.js' ),\n\tactionParams = require( './actionParams' );\n\n/**\n * API for providing language data.\n *\n * @class module:mobile.startup/languages~LanguageInfo\n */\nclass LanguageInfo {\n\t/**\n\t * @param {mw.Api} api\n\t */\n\tconstructor( api ) {\n\t\tthis.api = api;\n\t}\n\n\t/**\n\t * Get languageinfo API data from the local wiki, and transform it into a\n\t * format usable by LanguageSearcher.\n\t *\n\t * @memberof module:mobile.startup/languages~LanguageInfo\n\t * @instance\n\t * @returns {jQuery.Deferred}\n\t */\n\tgetLanguages() {\n\t\treturn this.api.get( actionParams( {\n\t\t\tmeta: 'languageinfo',\n\t\t\tliprop: 'code|autonym|name|bcp47'\n\t\t} ) ).then( ( resp ) => {\n\t\t\tconst filteredLanguages = [];\n\t\t\t// Filter out legacy languages and require an autonym.\n\t\t\t// If the bcp47 (https://w.wiki/Y7A) does not match the language\n\t\t\t// code, that is in an indication that the language code is outdated\n\t\t\t// and should not be used.\n\t\t\tObject.keys( resp.query.languageinfo ).forEach( ( key ) => {\n\t\t\t\tconst language = resp.query.languageinfo[key];\n\t\t\t\tif ( ( language.code.toLowerCase() === language.bcp47.toLowerCase() ) &&\n\t\t\t\t\tlanguage.autonym ) {\n\t\t\t\t\tfilteredLanguages.push( language );\n\t\t\t\t}\n\t\t\t} );\n\t\t\treturn filteredLanguages;\n\t\t}, () => util.Deferred().reject() ).then( ( filteredLanguages ) => ( {\n\t\t\tlanguages: filteredLanguages.map( ( data ) => {\n\t\t\t\tdata.url = '#';\n\t\t\t\tdata.lang = data.code;\n\t\t\t\tdata.langname = data.name;\n\t\t\t\t// FIXME: This isn't a \"title\" in the sense of a MediaWiki\n\t\t\t\t// Title, and it is rendered as a subheader in the list\n\t\t\t\t// item, so a different name would be wiser, both here and\n\t\t\t\t// in LanguageSearcher's template. Also it would arguably\n\t\t\t\t// be more intuitive for the language name (localized) to\n\t\t\t\t// appear as the main emphasized element of each language\n\t\t\t\t// list element; but instead the autonym has that role.\n\t\t\t\t// A more thorough refactoring of LanguageSearcher to allow\n\t\t\t\t// for generic header/subheader elements is left for a\n\t\t\t\t// follow-up.\n\t\t\t\tdata.title = data.name;\n\t\t\t\treturn data;\n\t\t\t} )\n\t\t} ), () => util.Deferred().reject() );\n\t}\n}\n\nmodule.exports = LanguageInfo;\n","const\n\tView = require( './View' ),\n\tutil = require( './util' );\n\n/**\n * Render CSS version of Codex message component.\n */\nclass MessageBox extends View {\n\t/**\n\t * @inheritdoc\n\t */\n\tconstructor( props ) {\n\t\tsuper( props );\n\t}\n\n\t/**\n\t * @inheritdoc\n\t */\n\tget isTemplateMode() {\n\t\treturn true;\n\t}\n\n\t/**\n\t * @mixes module:mobile.startup/View#defaults\n\t * @property {Object} defaults Default options hash.\n\t * @property {string} [defaults.heading] heading to show along with message (text)\n\t * @property {string} defaults.msg message to show (html)\n\t * @property {string} defaults.type either error, notice or warning\n\t * @property {string} defaults.className\n\t */\n\tget defaults() {\n\t\treturn {};\n\t}\n\n\tget template() {\n\t\treturn util.template( `\n<div\n  class=\"cdx-message cdx-message--block cdx-message--{{type}} {{className}}\"\n  aria-live=\"polite\"\n>\n  <!-- Empty span for message icon. -->\n  <span class=\"cdx-message__icon\"></span>\n  <!-- Div for content. -->\n  <div class=\"cdx-message__content\">\n  {{#heading}}<h2>{{heading}}</h2>{{/heading}}\n  {{{msg}}}\n  </div>\n</div>\n\t` );\n\t}\n}\n\nmodule.exports = MessageBox;\n","const util = require( './util.js' ),\n\tView = require( './View' );\n\n/**\n * Builds a section of a page\n */\nclass Section extends View {\n\t/**\n\t * @param {Object} options Configuration options\n\t */\n\tconstructor( options ) {\n\t\toptions.tag = 'h' + options.level;\n\t\tsuper( options );\n\t\tthis.line = options.line;\n\t\tthis.text = options.text;\n\t\tthis.hasReferences = options.hasReferences || false;\n\t\tthis.id = options.id || null;\n\t\tthis.anchor = options.anchor;\n\t\tthis.subsections = [];\n\t\t( options.subsections || [] ).forEach( ( section ) => this.subsections.push(\n\t\t\tnew Section( section ) ) );\n\t}\n\n\tget template() {\n\t\treturn util.template( `\n<h{{level}} id=\"{{anchor}}\">{{{line}}}</h{{level}}>\n{{{text}}}\n\t` );\n\t}\n\n\t/**\n\t * @mixes module:mobile.startup/View#defaults\n\t * @property {Object} defaults Default options hash.\n\t * @property {string} defaults.text Section text.\n\t */\n\tget defaults() {\n\t\treturn {\n\t\t\tline: undefined,\n\t\t\ttext: ''\n\t\t};\n\t}\n}\n\nmodule.exports = Section;\n","/**\n * Return the language code of the device in lowercase\n *\n * @ignore\n * @param {window.navigator} navigator\n * @return {string|undefined}\n */\nfunction getDeviceLanguage( navigator ) {\n\tconst lang = navigator.languages ?\n\t\tnavigator.languages[ 0 ] :\n\t\tnavigator.language || navigator.userLanguage ||\n\t\t\t\tnavigator.browserLanguage || navigator.systemLanguage;\n\n\treturn lang ? lang.toLowerCase() : undefined;\n}\n\nmodule.exports = getDeviceLanguage;\n","const\n\tm = require( '../moduleLoaderSingleton' ),\n\tgetDeviceLanguage = require( './getDeviceLanguage' ),\n\tOverlay = require( '../Overlay' ),\n\tpromisedView = require( '../promisedView' );\n\n/**\n * @ignore\n * @param {LanguageInfo} languageInfo\n * @param {boolean} showSuggestedLanguages If the suggested languages section\n * should be rendered.\n * @return {jQuery.Promise} Resolves to LanguageSearcher\n */\nfunction loadLanguageInfoSearcher( languageInfo, showSuggestedLanguages ) {\n\treturn mw.loader.using( 'mobile.languages.structured' ).then( () => languageInfo.getLanguages() ).then( ( data ) => {\n\t\tconst LanguageSearcher = m.require( 'mobile.languages.structured/LanguageSearcher' );\n\t\treturn new LanguageSearcher( {\n\t\t\tlanguages: data.languages,\n\t\t\tvariants: data.variants,\n\t\t\tshowSuggestedLanguages,\n\t\t\tdeviceLanguage: getDeviceLanguage( navigator )\n\t\t} );\n\n\t} );\n}\n\n/**\n * Factory function that returns a language info featured instance of an Overlay\n *\n * @ignore\n * @function\n * @memberof module:mobile.startup/languages\n * @param {module:mobile.startup/languages~LanguageInfo} languageInfo\n * @param {boolean} showSuggestedLanguages If the suggested languages section\n * should be rendered.\n * @return {module:mobile.startup/Overlay}\n */\nfunction languageInfoOverlay( languageInfo, showSuggestedLanguages ) {\n\treturn Overlay.make(\n\t\t{\n\t\t\theading: mw.msg( 'mobile-frontend-language-heading' ),\n\t\t\tclassName: 'overlay language-info-overlay'\n\t\t}, promisedView( loadLanguageInfoSearcher( languageInfo, showSuggestedLanguages ) )\n\t);\n}\n\n// To make knowing when async logic has resolved easier in tests\nlanguageInfoOverlay.test = {\n\tloadLanguageInfoSearcher\n};\n\nmodule.exports = languageInfoOverlay;\n","const\n\tm = require( '../moduleLoaderSingleton' ),\n\tgetDeviceLanguage = require( './getDeviceLanguage' ),\n\tOverlay = require( '../Overlay' ),\n\tMessageBox = require( '../MessageBox' ),\n\tcurrentPageHTMLParser = require( '../currentPageHTMLParser' )(),\n\tpromisedView = require( '../promisedView' );\n\n/**\n * @ignore\n * @return {jQuery.Promise} Resolves to LanguageSearcher\n */\nfunction loadLanguageSearcher() {\n\treturn mw.loader.using( 'mobile.languages.structured' ).then( () => currentPageHTMLParser.getLanguages(\n\t\tmw.config.get( 'wgTitle' )\n\t) ).then( ( data ) => {\n\t\tconst LanguageSearcher = m.require( 'mobile.languages.structured/LanguageSearcher' );\n\n\t\treturn new LanguageSearcher( {\n\t\t\tlanguages: data.languages,\n\t\t\tvariants: data.variants,\n\t\t\tshowSuggestedLanguages: true,\n\t\t\tdeviceLanguage: getDeviceLanguage( navigator ),\n\t\t\t/**\n\t\t\t * Stable for use inside ContentTranslation.\n\t\t\t *\n\t\t\t * @event ~'mobileFrontend.languageSearcher.onOpen'\n\t\t\t * @memberof Hooks\n\t\t\t * @param {Hooks~LanguageSearcher} searcher\n\t\t\t */\n\t\t\tonOpen: ( searcher ) => mw.hook( 'mobileFrontend.languageSearcher.onOpen' ).fire( searcher )\n\t\t} );\n\t}, () => new MessageBox( {\n\t\ttype: 'error',\n\t\tclassName: 'content',\n\t\tmsg: mw.msg( 'mobile-frontend-languages-structured-overlay-error' )\n\t} ) );\n}\n\n/**\n * Factory function that returns a language featured instance of an Overlay.\n *\n * @function\n * @memberof module:mobile.startup/languages\n * @return {module:mobile.startup/Overlay}\n */\nfunction languageOverlay() {\n\treturn Overlay.make(\n\t\t{\n\t\t\theading: mw.msg( 'mobile-frontend-language-heading' ),\n\t\t\tclassName: 'overlay language-overlay'\n\t\t}, promisedView( loadLanguageSearcher() )\n\t);\n}\n\n// To make knowing when async logic has resolved easier in tests\nlanguageOverlay.test = {\n\tloadLanguageSearcher\n};\n\nmodule.exports = languageOverlay;\n","/**\n * Internal for use inside Minerva only. See {@link module:mobile.startup} for access.\n *\n * @module mobile.startup/mediaViewer\n */\nconst m = require( '../moduleLoaderSingleton' ),\n\tpromisedView = require( '../promisedView' ),\n\tutil = require( '../util' ),\n\theader = require( '../headers' ).header,\n\ticons = require( '../icons' ),\n\tOverlay = require( '../Overlay' );\n\n/**\n * Produce an overlay for mediaViewer\n *\n * @name overlay\n * @memberof module:mobile.startup/mediaViewer\n * @param {Object} options\n * @return {module:mobile.startup/Overlay}\n */\nfunction mediaViewerOverlay( options ) {\n\tconst overlay = Overlay.make(\n\t\t{\n\t\t\theaders: [\n\t\t\t\theader( '', [], icons.cancel( 'gray' ) )\n\t\t\t],\n\t\t\tclassName: 'overlay media-viewer'\n\t\t},\n\t\tpromisedView(\n\t\t\tutil.Promise.all( [\n\t\t\t\tmw.loader.using( 'mobile.mediaViewer' )\n\t\t\t] ).then( () => {\n\t\t\t\tconst ImageCarousel = m.require( 'mobile.mediaViewer' ).ImageCarousel;\n\t\t\t\treturn new ImageCarousel( options );\n\t\t\t} )\n\t\t)\n\t);\n\n\treturn overlay;\n}\n\nmodule.exports = mediaViewerOverlay;\n","const currentPageHTMLParser = require( './currentPageHTMLParser' );\nconst time = require( './time' );\nconst LanguageInfo = require( './LanguageInfo' );\nconst currentPage = require( './currentPage' );\nconst Drawer = require( './Drawer' );\nconst CtaDrawer = require( './CtaDrawer' );\nconst lazyImageLoader = require( './lazyImages/lazyImageLoader' );\nconst icons = require( './icons' );\nconst PageHTMLParser = require( './PageHTMLParser' );\nconst showOnPageReload = require( './showOnPageReload' );\nconst OverlayManager = require( './OverlayManager' );\nconst View = require( './View' );\nconst Overlay = require( './Overlay' );\nconst references = require( './references/references' );\nconst search = {\n\tSearchOverlay: require( './search/SearchOverlay' ),\n\tSearchGateway: require( './search/SearchGateway' )\n};\nconst promisedView = require( './promisedView' );\nconst headers = require( './headers' );\nconst Skin = require( './Skin' );\nconst mediaViewer = {\n\toverlay: require( './mediaViewer/overlay' )\n};\nconst languageInfoOverlay = require( './languageOverlay/languageInfoOverlay' );\nconst languageOverlay = require( './languageOverlay/languageOverlay' );\nconst amcOutreach = require( './amcOutreach/amcOutreach' );\nconst util = require( './util.js' );\nconst actionParams = require( './actionParams.js' );\nconst Icon = require( './Icon.js' );\nconst IconButton = require( './IconButton.js' );\nconst MessageBox = require( './MessageBox.js' );\nconst Section = require( './Section.js' );\nconst Button = require( './Button.js' );\n\n// Expose chunk to temporary variable which will be deleted and exported via ResourceLoader\n// package inside mobile.startup.exports.\n\n/**\n * The main library for accessing MobileFrontend's stable APIs.\n *\n * @module mobile.startup\n */\nmodule.exports = {\n\t/**\n\t * Internal, strictly for use inside MobileFrontend only\n\t *\n\t * @private\n\t */\n\tactionParams,\n\t/**\n\t * Internal, strictly for use inside MobileFrontend only\n\t *\n\t * @memberof module:mobile.startup\n\t * @type module:mobile.startup/util\n\t * @private\n\t */\n\tutil,\n\t/**\n\t * Internal for use inside Minerva only\n\t *\n\t * @memberof module:mobile.startup\n\t * @type module:mobile.startup/AmcOutreach\n\t */\n\n\tamcOutreach,\n\t/**\n\t * @private for use inside MobileFrontend only.\n\t */\n\theaders,\n\t// Internal for use inside GrowthExperiments only.\n\toverlayHeader: headers.header,\n\t/**\n\t * Internal for use inside Minerva, GrowthExperiments only.\n\t *\n\t * @type module:mobile.startup/Drawer\n\t */\n\tDrawer,\n\t// Internal for use inside Minerva only.\n\tCtaDrawer,\n\t/**\n\t * @internal for use strictly inside MobileFrontend only. Other extensions\n\t *  should use View.make and Overlay.make\n\t */\n\tclass: {\n\t\tView,\n\t\tOverlay,\n\t\tSection,\n\t\tMessageBox,\n\t\tIcon,\n\t\tIconButton,\n\t\tButton\n\t},\n\t/**\n\t * @stable for use\n\t * @memberof module:mobile.startup\n\t * @type module:mobile.startup/View\n\t */\n\tView: {\n\t\tmake: View.make\n\t},\n\t/**\n\t * @stable for use\n\t * @memberof module:mobile.startup\n\t * @type module:mobile.startup/Overlay\n\t */\n\tOverlay: {\n\t\tmake: Overlay.make\n\t},\n\t/**\n\t * Internal for use inside Minerva only.\n\t *\n\t * @memberof module:mobile.startup\n\t * @type module:mobile.startup/PageHTMLParser\n\t */\n\tcurrentPageHTMLParser,\n\t/**\n\t * Internal for use inside Minerva, ExternalGuidance and Echo only.\n\t *\n\t * @memberof module:mobile.startup\n\t * @return {module:mobile.startup/OverlayManager}\n\t */\n\tgetOverlayManager: () => OverlayManager.getSingleton(),\n\t/**\n\t * Internal for use inside Minerva only.\n\t *\n\t * @type module:mobile.startup/Page\n\t * @memberof module:mobile.startup\n\t */\n\tcurrentPage,\n\t/**\n\t * Internal for use inside Minerva only.\n\t *\n\t * @type module:mobile.startup/PageHTMLParser\n\t * @memberof module:mobile.startup\n\t */\n\tPageHTMLParser,\n\t/**\n\t * Internal for use inside Minerva only.\n\t *\n\t * @type module:mobile.startup/Icon\n\t * @memberof module:mobile.startup\n\t */\n\tspinner: icons.spinner,\n\t/**\n\t * Internal for use inside MobileFrontend only\n\t *\n\t * @private\n\t */\n\tcancelIcon: icons.cancel,\n\t/**\n\t * Internal for use inside Minerva only.\n\t *\n\t * @memberof module:mobile.startup\n\t * @type module:mobile.startup/mediaViewer\n\t */\n\tmediaViewer,\n\t/**\n\t * Internal for use inside Minerva only.\n\t *\n\t * @memberof module:mobile.startup\n\t * @type module:mobile.startup/references\n\t */\n\treferences,\n\t/**\n\t * Internal for use inside Minerva only.\n\t *\n\t * @memberof module:mobile.startup\n\t * @type module:mobile.startup/search\n\t */\n\tsearch,\n\t/**\n\t * Internal for use inside Minerva only.\n\t *\n\t * @memberof module:mobile.startup\n\t * @type module:mobile.startup/time\n\t */\n\ttime,\n\t// Internal for use inside Echo, GrowthExperiments only.\n\tpromisedView,\n\t/**\n\t * Loads all images on the page, stable to call.\n\t *\n\t * @memberof module:mobile.startup\n\t * @return {jQuery.Deferred}\n\t */\n\tloadAllImagesInPage: () => lazyImageLoader.loadImages(\n\t\tlazyImageLoader.queryPlaceholders( document.getElementById( 'content' ) )\n\t),\n\t/**\n\t * Show a notification on page reload, internal for Minerva\n\t *\n\t * @memberof module:mobile.startup\n\t * @param {string} msg\n\t * @return {jQuery.Deferred}\n\t */\n\tnotifyOnPageReload: ( msg ) => showOnPageReload( msg ),\n\t/**\n\t * Internal for use inside VisualEditor\n\t *\n\t * @memberof module:mobile.startup\n\t * @return {string|undefined}\n\t */\n\tlicense() {\n\t\tconst skin = Skin.getSingleton();\n\t\treturn skin.getLicenseMsg();\n\t},\n\t/**\n\t * Internal for use inside Minerva. See {@link module:mobile.startup} for access.\n\t *\n\t * @module mobile.startup/languages\n\t */\n\t/**\n\t * Access to language overlays for usage inside Minerva only.\n\t *\n\t * @memberof module:mobile.startup\n\t * @type module:mobile.startup/languages\n\t */\n\tlanguages: {\n\t\tlanguageOverlay,\n\t\t/**\n\t\t * Shows information about suggested languages.\n\t\t *\n\t\t * @memberof module:mobile.startup/languages\n\t\t * @param {mw.Api} api\n\t\t * @param {boolean} showSuggestedLanguage If the suggested languages section\n\t\t * should be rendered.\n\t\t */\n\t\tlanguageInfoOverlay( api, showSuggestedLanguage ) {\n\t\t\treturn languageInfoOverlay( new LanguageInfo( api ), showSuggestedLanguage );\n\t\t}\n\t}\n};\n","const\n\ticons = require( './icons' ),\n\tView = require( './View' );\n\n/**\n * Internal for use inside Echo, GrowthExperiments only.\n * It's a view that spins until the promise resolves!\n * If the promise successfully resolves, the newView will be shown. if the\n * promise rejects and rejects to a view, the errorView will be shown.\n *\n * @function promisedView\n * @memberof module:mobile.startup\n * @param {jQuery.Promise} promise\n * @return {module:mobile.startup/View}\n */\nmodule.exports = function promisedView( promise ) {\n\tconst view = new View( {\n\t\tclassName: 'promised-view'\n\t} );\n\tview.$el.append( icons.spinner().$el );\n\tpromise.then( ( newView ) => {\n\t\tview.$el.replaceWith( newView.$el );\n\t\t// update the internal reference.\n\t\tview.$el = newView.$el;\n\t}, ( errorView ) => {\n\t\tif ( !errorView || !errorView.$el ) {\n\t\t\t// return early to keep backwards compatibility with clients of\n\t\t\t// promisedView that do not reject to an error view\n\t\t\treturn;\n\t\t}\n\n\t\tview.$el.replaceWith( errorView.$el );\n\t\t// update the internal reference.\n\t\tview.$el = errorView.$el;\n\t} );\n\n\treturn view;\n};\n","/**\n * Abstract base class\n * Gateway for retrieving references\n *\n * @class module:mobile.startup/references~Gateway\n * @abstract\n */\nclass ReferencesGateway {\n\t/**\n\t * @param {mw.Api} api\n\t */\n\tconstructor( api ) {\n\t\tthis.api = api;\n\t}\n\n\t// eslint-disable-next-line jsdoc/require-returns-check\n\t/**\n\t * Return the matched reference via API or DOM query\n\t *\n\t * @memberof module:mobile.startup/references~Gateway\n\t * @instance\n\t * @param {string} id CSS selector\n\t * @param {Page} page to find reference for\n\t * @param {module:mobile.startup/PageHTMLParser} pageHTMLParser\n\t * @return {jQuery.Promise} resolves with an Object representing reference\n\t *  with a `text` property\n\t *  The promise should be rejected with ReferenceGateway.ERROR_NOT_EXIST:\n\t *  if the reference is not found.\n\t *  If for some reason locating the reference fails return ReferenceGateway.ERROR_OTHER.\n\t */\n\t// eslint-disable-next-line no-unused-vars\n\tgetReference( id, page, pageHTMLParser ) {\n\t\t// overridden\n\t}\n}\n\n/**\n * @memberof module:mobile.startup/references~Gateway\n * @property ERROR_NOT_EXIST error code to be returned by getReference\n *  when a reference does not exist.\n * @type string\n */\nReferencesGateway.ERROR_NOT_EXIST = 'NOT_EXIST_ERROR';\n/**\n * ERROR_OTHER error code to be returned by getReference\n *  under any other circumstance not covered\n *  by ERROR_NOT_EXIST. It should be used if it is unclear whether a reference exists or not.\n *\n * @memberof module:mobile.startup/references~Gateway\n * @type string\n */\nReferencesGateway.ERROR_OTHER = 'OTHER_ERROR';\n\nmodule.exports = ReferencesGateway;\n","const ReferencesGateway = require( './ReferencesGateway' ),\n\tutil = require( './../util' );\n\n/**\n * Gateway for retrieving references via the content of the Page\n *\n * @memberof module:mobile.startup/references\n * @inheritdoc\n */\nclass ReferencesHtmlScraperGateway extends ReferencesGateway {\n\tconstructor() {\n\t\tsuper( arguments );\n\t\t/**\n\t\t * @memberof ReferencesHtmlScraperGateway\n\t\t * @property EXTERNAL_LINK_CLASS a CSS class to place on external links\n\t\t * in addition to the default 'external' class.\n\t\t */\n\t\tthis.EXTERNAL_LINK_CLASS = 'external--reference';\n\t}\n\n\t/**\n\t * @param {string} id ID of a DOM element in the page.\n\t * @param {jQuery.Object} $container to scan for an element\n\t * @return {jQuery.Promise} that can be used by getReference\n\t */\n\tgetReferenceFromContainer( id, $container ) {\n\t\tconst result = util.Deferred();\n\n\t\tconst $el = $container.find( '#' + util.escapeSelector( id ) );\n\t\tif ( $el.length ) {\n\t\t\tlet $parent;\n\n\t\t\t// This finds either the inner <ol class=\"mw-extended-references\">, or the outer\n\t\t\t// <ol class=\"references\">\n\t\t\tconst $ol = $el.closest( 'ol' );\n\t\t\tconst isSubref = $ol.hasClass( 'mw-extended-references' );\n\t\t\tif ( isSubref ) {\n\t\t\t\t$parent = $ol.parent();\n\t\t\t}\n\t\t\t// The following classes are used here:\n\t\t\t// * external--reference\n\t\t\t// * other values of EXTERNAL_LINK_CLASS in sub-classes\n\t\t\t( $parent || $el ).find( '.external' ).addClass( this.EXTERNAL_LINK_CLASS );\n\t\t\tresult.resolve( {\n\t\t\t\ttext: this.getReferenceHtml( $el ),\n\t\t\t\tparentText: this.getReferenceHtml( $parent ),\n\t\t\t\tisSubref\n\t\t\t} );\n\t\t} else {\n\t\t\tresult.reject( ReferencesGateway.ERROR_NOT_EXIST );\n\t\t}\n\t\treturn result.promise();\n\t}\n\n\t/**\n\t * @memberof ReferencesHtmlScraperGateway\n\t * @param {jQuery.Object|undefined} $reference\n\t * @return {string|undefined}\n\t */\n\tgetReferenceHtml( $reference ) {\n\t\treturn $reference ?\n\t\t\t$reference.children( '.mw-reference-text, .reference-text' ).first().html() :\n\t\t\t'';\n\t}\n\n\t/**\n\t * @inheritdoc\n\t * @param {string} hash Hash fragment with leading '#'\n\t * @param {Page} page (unused)\n\t * @param {module:mobile.startup/PageHTMLParser} pageHTMLParser\n\t */\n\tgetReference( hash, page, pageHTMLParser ) {\n\t\tconst id = mw.util.percentDecodeFragment( hash.slice( 1 ) );\n\t\t// If an id is not found it's possible the id passed needs decoding (per T188547).\n\t\treturn this.getReferenceFromContainer( id, pageHTMLParser.$el.find( 'ol.references' ) );\n\t}\n}\n\nmodule.exports = ReferencesHtmlScraperGateway;\n","const Drawer = require( '../Drawer' ),\n\tutil = require( '../util' ),\n\ticons = require( '../icons' ),\n\tReferencesGateway = require( './ReferencesGateway' ),\n\tIcon = require( '../Icon' ),\n\tReferencesHtmlScraperGateway = require( './ReferencesHtmlScraperGateway' ),\n\tIconButton = require( '../IconButton' );\n\n/**\n * Create a callback for clicking references\n *\n * @ignore\n * @param {Function} onNestedReferenceClick\n * @return {Function}\n */\nfunction makeOnNestedReferenceClickHandler( onNestedReferenceClick ) {\n\treturn ( ev ) => {\n\t\tconst target = ev.currentTarget.querySelector( 'a' );\n\t\tif ( target ) {\n\t\t\tonNestedReferenceClick(\n\t\t\t\ttarget.getAttribute( 'href' ),\n\t\t\t\ttarget.textContent\n\t\t\t);\n\t\t\t// Don't hide the already shown drawer via propagation\n\t\t\treturn false;\n\t\t}\n\t};\n}\n\n/**\n * Drawer for references\n *\n * @memberof module:mobile.startup/references\n * @uses IconButton\n * @param {Object} props\n * @param {boolean} [props.error] whether an error has occurred\n * @param {string} props.title of reference e.g [1]\n * @param {string} props.text is the HTML of the reference\n * @param {string} [props.parentText] is the HTML of the parent reference if there is one\n * @param {boolean} props.isSubref true when this reference has a parent\n * @param {Function} [props.onNestedReferenceClick] callback for when a reference\n *  inside the reference is clicked.\n * @return {module:mobile.startup/Drawer}\n */\nfunction referenceDrawer( props ) {\n\tconst errorIcon = props.error ? new IconButton( {\n\t\tname: 'error',\n\t\tisSmall: true\n\t} ).$el : null;\n\n\tconst mainRef = props.isSubref ? props.parentText : props.text;\n\tconst mainRefHtml = util.parseHTML( '<div>' )\n\t\t.addClass( 'main-reference-content' )\n\t\t.html( mainRef );\n\tif ( !mainRef ) {\n\t\tmainRefHtml.append( icons.spinner().$el );\n\t}\n\tconst subRefHtml = props.isSubref ?\n\t\tutil.parseHTML( '<div>' ).html( props.text ) : '';\n\n\treturn new Drawer(\n\t\tutil.extend(\n\t\t\t{\n\t\t\t\tshowCollapseIcon: false,\n\t\t\t\tclassName: 'drawer position-fixed text references-drawer',\n\t\t\t\tevents: {\n\t\t\t\t\t'click sup a': ( ev ) => {\n\t\t\t\t\t\t// Stop default scroll to hash fragment behaviour.\n\t\t\t\t\t\tev.preventDefault();\n\t\t\t\t\t},\n\t\t\t\t\t'click sup': props.onNestedReferenceClick &&\n\t\t\t\t\t\tmakeOnNestedReferenceClickHandler( props.onNestedReferenceClick )\n\t\t\t\t},\n\t\t\t\tchildren: [\n\t\t\t\t\tutil.parseHTML( '<div>' )\n\t\t\t\t\t\t.addClass( 'references-drawer__header' )\n\t\t\t\t\t\t.append( [\n\t\t\t\t\t\t\tnew Icon( {\n\t\t\t\t\t\t\t\ticon: 'reference',\n\t\t\t\t\t\t\t\tisSmall: true\n\t\t\t\t\t\t\t} ).$el,\n\t\t\t\t\t\t\tutil.parseHTML( '<span>' ).addClass( 'references-drawer__title' ).text( mw.msg( 'mobile-frontend-references-citation' ) ),\n\t\t\t\t\t\t\ticons.cancel( 'gray', {\n\t\t\t\t\t\t\t\tisSmall: true,\n\t\t\t\t\t\t\t\tadditionalClassNames: 'mf-button-flush-right'\n\t\t\t\t\t\t\t} ).$el\n\t\t\t\t\t\t] ),\n\n\t\t\t\t\t// Add .mw-parser-output so that TemplateStyles styles apply (T244510)\n\t\t\t\t\tutil.parseHTML( '<div>' ).addClass( 'mw-parser-output' ).append( [\n\t\t\t\t\t\terrorIcon,\n\t\t\t\t\t\tutil.parseHTML( '<sup>' ).text( props.title ),\n\t\t\t\t\t\tmainRefHtml,\n\t\t\t\t\t\tsubRefHtml\n\t\t\t\t\t] )\n\t\t\t\t]\n\t\t\t},\n\t\t\tprops\n\t\t)\n\t);\n}\n\n/**\n * Internal for use inside Minerva only. See {@link module:mobile.startup} for access.\n *\n * @exports module:mobile.startup/references\n */\nconst references = {\n\ttest: {\n\t\tmakeOnNestedReferenceClickHandler\n\t},\n\tReferencesHtmlScraperGateway,\n\treferenceDrawer,\n\t/**\n\t * Fetch and render nested reference upon click\n\t *\n\t * @param {string} id of the reference to be retrieved\n\t * @param {Page} page to locate reference for\n\t * @param {string} refNumber the number it identifies as in the page\n\t * @param {module:mobile.startup/PageHTMLParser} pageHTMLParser\n\t * @param {module:mobile.startup/references~Gateway} gateway\n\t * @param {Object} props for referenceDrawer\n\t * @param {Function} onShowNestedReference function call when a nested reference is triggered.\n\t * @return {jQuery.Deferred}\n\t */\n\tshowReference( id, page, refNumber, pageHTMLParser, gateway, props,\n\t\tonShowNestedReference\n\t) {\n\t\treturn gateway.getReference( id, page, pageHTMLParser ).then( ( reference ) => {\n\t\t\tconst drawer = referenceDrawer( util.extend( {\n\t\t\t\ttitle: refNumber,\n\t\t\t\ttext: reference.text,\n\t\t\t\tparentText: reference.parentText,\n\t\t\t\tisSubref: reference.isSubref,\n\t\t\t\tonNestedReferenceClick( href, text ) {\n\t\t\t\t\treferences.showReference(\n\t\t\t\t\t\thref,\n\t\t\t\t\t\tpage,\n\t\t\t\t\t\ttext,\n\t\t\t\t\t\tpageHTMLParser,\n\t\t\t\t\t\tgateway\n\t\t\t\t\t).then( ( nestedDrawer ) => {\n\t\t\t\t\t\tif ( props.onShowNestedReference ) {\n\t\t\t\t\t\t\tonShowNestedReference( drawer, nestedDrawer );\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tmw.log.warn( 'Please provide onShowNestedReferences parameter.' );\n\t\t\t\t\t\t\tdocument.body.appendChild( nestedDrawer.$el[0] );\n\t\t\t\t\t\t\tdrawer.hide();\n\t\t\t\t\t\t\tnestedDrawer.show();\n\t\t\t\t\t\t}\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}, props ) );\n\t\t\treturn drawer;\n\t\t}, ( err ) => {\n\t\t\t// If non-existent reference nothing to do.\n\t\t\tif ( err === ReferencesGateway.ERROR_NOT_EXIST ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\treturn referenceDrawer( {\n\t\t\t\terror: true,\n\t\t\t\ttitle: refNumber,\n\t\t\t\ttext: mw.msg( 'mobile-frontend-references-citation-error' )\n\t\t\t} );\n\t\t} );\n\t}\n};\n\nmodule.exports = references;\n","/**\n * Internal for use inside Minerva only. See {@link module:mobile.startup} for access.\n *\n * @module module:mobile.startup/search\n */\nconst\n\tpageJSONParser = require( '../page/pageJSONParser' ),\n\tutil = require( '../util' ),\n\textendSearchParams = require( '../extendSearchParams' );\n\n/**\n * Interact with MediaWiki search API.\n *\n * @memberof module:mobile.startup/search\n * @uses mw.Api\n * @param {mw.Api} api\n */\nclass SearchGateway {\n\t/**\n\t * @param {mw.Api} api\n\t */\n\tconstructor( api ) {\n\t\tthis.api = api;\n\t\tthis.searchCache = {};\n\t\tthis.generator = mw.config.get( 'wgMFSearchGenerator' );\n\t\t/**\n\t\t * The namespace to search in.\n\t\t *\n\t\t * @type {number}\n\t\t */\n\t\tthis.searchNamespace = 0;\n\t}\n\n\t/**\n\t * Get the data used to do the search query api call.\n\t *\n\t * @param {string} query to search for\n\t * @return {Object}\n\t */\n\tgetApiData( query ) {\n\t\tconst prefix = this.generator.prefix,\n\t\t\tdata = extendSearchParams( 'search', {\n\t\t\t\tgenerator: this.generator.name\n\t\t\t} );\n\n\t\tdata.redirects = '';\n\n\t\tdata['g' + prefix + 'search'] = query;\n\t\tdata['g' + prefix + 'namespace'] = this.searchNamespace;\n\t\tdata['g' + prefix + 'limit'] = 15;\n\n\t\t// If PageImages is being used configure further.\n\t\tif ( data.pilimit ) {\n\t\t\tdata.pilimit = 15;\n\t\t\tdata.pithumbsize = mw.config.get( 'wgMFThumbnailSizes' ).tiny;\n\t\t}\n\t\treturn data;\n\t}\n\n\t/**\n\t * Escapes regular expression wildcards (metacharacters) by adding a \\\\ prefix\n\t *\n\t * @param {string} str a string\n\t * @return {Object} a regular expression that can be used to search for that str\n\t * @private\n\t */\n\t_createSearchRegEx( str ) {\n\t\t// '\\[' can be unescaped, but leave it balanced with '`]'\n\t\t// eslint-disable-next-line no-useless-escape\n\t\tstr = str.replace( /[-\\[\\]{}()*+?.,\\\\^$|#\\s]/g, '\\\\$&' );\n\t\treturn new RegExp( '^(' + str + ')', 'ig' );\n\t}\n\n\t/**\n\t * Takes a label potentially beginning with term\n\t * and highlights term if it is present with strong\n\t *\n\t * @param {string} label a piece of text\n\t * @param {string} term a string to search for from the start\n\t * @return {string} safe html string with matched terms encapsulated in strong tags\n\t * @private\n\t */\n\t_highlightSearchTerm( label, term ) {\n\t\tlabel = util.parseHTML( '<span>' ).text( label ).html();\n\t\tterm = term.trim();\n\t\tterm = util.parseHTML( '<span>' ).text( term ).html();\n\n\t\treturn label.replace( this._createSearchRegEx( term ), '<strong>$1</strong>' );\n\t}\n\n\t/**\n\t * Return data used for creating {Page} objects\n\t *\n\t * @param {string} query to search for\n\t * @param {Object} pageInfo from the API\n\t * @return {Object} data needed to create a {Page}\n\t * @private\n\t */\n\t_getPage( query, pageInfo ) {\n\t\tconst page = pageJSONParser.parse( pageInfo );\n\n\t\t// If displaytext is set in the generator result (eg. by Wikibase),\n\t\t// use that as display title.\n\t\t// Otherwise default to the page's title.\n\t\t// FIXME: Given that displayTitle could have html in it be safe and just highlight text.\n\t\t// Note that highlightSearchTerm does full HTML escaping before highlighting.\n\t\tpage.displayTitle = this._highlightSearchTerm(\n\t\t\tpageInfo.displaytext ? pageInfo.displaytext : page.title,\n\t\t\tquery\n\t\t);\n\t\tpage.index = pageInfo.index;\n\n\t\treturn page;\n\t}\n\n\t/**\n\t * Process the data returned by the api call.\n\t *\n\t * @param {string} query to search for\n\t * @param {Object} data from api\n\t * @return {Array}\n\t * @private\n\t */\n\t_processData( query, data ) {\n\t\tlet results = [];\n\n\t\tif ( data.query ) {\n\n\t\t\tresults = data.query.pages || {};\n\t\t\tresults = Object.keys( results ).map( ( id ) => this._getPage( query, results[id] ) );\n\t\t\t// sort in order of index\n\t\t\tresults.sort( ( a, b ) => a.index - b.index );\n\t\t}\n\n\t\treturn results;\n\t}\n\n\t/**\n\t * Perform a search for the given query.\n\t *\n\t * @param {string} query to search for\n\t * @return {jQuery.Deferred}\n\t */\n\tsearch( query ) {\n\t\tconst scriptPath = mw.config.get( 'wgMFScriptPath' );\n\n\t\tif ( !this.isCached( query ) ) {\n\t\t\tconst xhr = this.api.get( this.getApiData( query ), scriptPath ? {\n\t\t\t\turl: scriptPath\n\t\t\t} : undefined );\n\t\t\tconst request = xhr\n\t\t\t\t.then(\n\t\t\t\t\t// resolve the Deferred object\n\t\t\t\t\t( data, jqXHR ) => ( {\n\t\t\t\t\t\tquery,\n\t\t\t\t\t\tresults: this._processData( query, data ),\n\t\t\t\t\t\tsearchId: jqXHR && jqXHR.getResponseHeader( 'x-search-id' )\n\t\t\t\t\t} ),\n\t\t\t\t\t() => {\n\t\t\t\t\t\t// reset cached result, it maybe contains no value\n\t\t\t\t\t\tthis.searchCache[query] = undefined;\n\t\t\t\t\t}\n\t\t\t\t);\n\n\t\t\t// cache the result to prevent the execution of one search query twice\n\t\t\t// in one session\n\t\t\tthis.searchCache[query] = request.promise( {\n\t\t\t\tabort() {\n\t\t\t\t\txhr.abort();\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\n\t\treturn this.searchCache[query];\n\t}\n\n\t/**\n\t * Check if the search has already been performed in given session.\n\t *\n\t * @param {string} query\n\t * @return {boolean}\n\t */\n\tisCached( query ) {\n\t\treturn Boolean( this.searchCache[query] );\n\t}\n}\n\nmodule.exports = SearchGateway;\n","const util = require( '../util' ),\n\tView = require( '../View' ),\n\tIconButton = require( '../IconButton' );\n\nclass SearchHeaderView extends View {\n\t/**\n\t * constructor\n\t *\n\t * @inheritdoc\n\t * @param {Object} props\n\t * @param {Function} props.onInput executed every time input changes\n\t * @param {string} props.placeholderMsg\n\t * @param {string} props.action\n\t * @parm {string} [props.autocapitalize] none or sentences\n\t * @param {string} [props.searchTerm] default\n\t */\n\tconstructor( props ) {\n\t\tsuper(\n\t\t\tutil.extend( {\n\t\t\t\tautocapitalize: 'sentences'\n\t\t\t}, props, {\n\t\t\t\tevents: {\n\t\t\t\t\t'input input': 'onInput'\n\t\t\t\t}\n\t\t\t} )\n\t\t);\n\t}\n\n\t/** @inheritdoc */\n\tonInput( ev ) {\n\t\tconst query = ev.target.value;\n\t\tthis.options.onInput( query );\n\t\tif ( query ) {\n\t\t\tthis.clearIcon.$el.show();\n\t\t} else {\n\t\t\tthis.clearIcon.$el.hide();\n\t\t}\n\t}\n\n\t/** @inheritdoc */\n\tget isTemplateMode() {\n\t\treturn true;\n\t}\n\n\t/** @inheritdoc */\n\tget template() {\n\t\treturn util.template( `<div class=\"overlay-title search-header-view\">\n\t\t<form method=\"get\" action=\"{{action}}\" class=\"search-box\">\n\t\t<input class=\"search mf-icon-search\" type=\"search\" name=\"search\" spellcheck=\"false\"\n\t\t\tautocapitalize=\"{{autocapitalize}}\"\n\t\t\tautocomplete=\"off\" placeholder=\"{{placeholderMsg}}\" aria-label=\"{{placeholderMsg}}\" value=\"{{searchTerm}}\">\n\t\t<input type=\"hidden\" name=\"title\" value=\"{{defaultSearchPage}}\">\n\t\t</form>\n</div>` );\n\t}\n\n\t/** @inheritdoc */\n\tpostRender() {\n\t\tconst clearIcon = new IconButton( {\n\t\t\ttagName: 'button',\n\t\t\ticon: 'clear',\n\t\t\tsize: 'medium',\n\t\t\tisSmall: true,\n\t\t\tlabel: mw.msg( 'mobile-frontend-clear-search' ),\n\t\t\tadditionalClassNames: 'clear',\n\t\t\tevents: {\n\t\t\t\tclick: () => {\n\t\t\t\t\tthis.$el.find( 'input' ).val( '' ).trigger( 'focus' );\n\t\t\t\t\tthis.options.onInput( '' );\n\t\t\t\t\tclearIcon.$el.hide();\n\t\t\t\t\t// In beta the clear button is on top of the search input.\n\t\t\t\t\t// Stop propagation so that the input doesn't receive the click.\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t\tthis.clearIcon = clearIcon;\n\t\tclearIcon.$el.hide();\n\t\tclearIcon.$el.attr( 'aria-hidden', 'true' );\n\t\tthis.$el.find( 'form' ).append( clearIcon.$el );\n\t}\n}\n\nmodule.exports = SearchHeaderView;\n","const\n\tOverlay = require( '../Overlay' ),\n\tutil = require( '../util' ),\n\tsearchHeader = require( './searchHeader' ),\n\tSearchResultsView = require( './SearchResultsView' ),\n\tWatchstarPageList = require( '../watchstar/WatchstarPageList' ),\n\tSEARCH_DELAY = 300,\n\tSEARCH_SPINNER_DELAY = 2000;\n\n/**\n * Overlay displaying search results\n *\n * @memberof module:mobile.startup/search\n * @uses SearchGateway\n * @uses IconButton\n */\nclass SearchOverlay extends Overlay {\n\t/**\n\t * @param {Object} params Configuration options\n\t * @param {string} params.placeholderMsg Search input placeholder text.\n\t * @param {string} [params.action] of form defaults to the value of wgScript\n\t * @param {string} [params.defaultSearchPage] The default search page e.g. Special:Search\n\t * @param {SearchGateway} [params.gateway]\n\t */\n\tconstructor( params ) {\n\t\tconst header = searchHeader(\n\t\t\t\tparams.placeholderMsg,\n\t\t\t\tparams.action || mw.config.get( 'wgScript' ),\n\t\t\t\t( query ) => this.performSearch( query ),\n\t\t\t\tparams.defaultSearchPage || '',\n\t\t\t\tparams.autocapitalize\n\t\t\t),\n\t\t\toptions = util.extend( true, {\n\t\t\t\theaderChrome: true,\n\t\t\t\tisBorderBox: false,\n\t\t\t\tclassName: 'overlay search-overlay',\n\t\t\t\theaders: [ header ],\n\t\t\t\tevents: {\n\t\t\t\t\t'click .search-content': 'onClickSearchContent',\n\t\t\t\t\t'click .overlay-content': 'onClickOverlayContent',\n\t\t\t\t\t'click .overlay-content > div': ( ev ) => {\n\t\t\t\t\t\tmw.hook( 'ext.wikimediaEvents.webUIClick.event' ).fire( ev );\n\t\t\t\t\t\tev.stopPropagation();\n\t\t\t\t\t},\n\t\t\t\t\t'touchstart .results': 'hideKeyboardOnScroll',\n\t\t\t\t\t'mousedown .results': 'hideKeyboardOnScroll',\n\t\t\t\t\t'click .results a': 'onClickResult'\n\t\t\t\t}\n\t\t\t},\n\t\t\tparams );\n\n\t\tsuper( options );\n\t\tthis.header = header;\n\n\t\tthis.api = options.api;\n\t\t// eslint-disable-next-line new-cap\n\t\tthis.gateway = options.gateway || new options.gatewayClass( this.api );\n\n\t\tthis.router = options.router;\n\n\t\tthis.currentSearchId = null;\n\t}\n\n\t/**\n\t * Initialize 'search within pages' functionality\n\t *\n\t */\n\tonClickSearchContent() {\n\t\tconst\n\t\t\t$form = this.$el.find( 'form' ),\n\t\t\t$el = $form[0].parentNode;\n\n\t\t// Add fulltext input to force fulltext search\n\t\tthis.parseHTML( '<input>' )\n\t\t\t.attr( {\n\t\t\t\ttype: 'hidden',\n\t\t\t\tname: 'fulltext',\n\t\t\t\tvalue: 'search'\n\t\t\t} )\n\t\t\t.appendTo( $form );\n\t\t// history.back queues a task so might run after this call. Thus we use setTimeout\n\t\t// http://www.w3.org/TR/2011/WD-html5-20110113/webappapis.html#queue-a-task\n\t\tsetTimeout( () => {\n\t\t\t// Firefox doesn't allow submission of a form not in the DOM\n\t\t\t// so temporarily re-add it if it's gone.\n\t\t\tif ( !$form[0].parentNode ) {\n\t\t\t\t$form.appendTo( $el );\n\t\t\t}\n\t\t\t$form.trigger( 'submit' );\n\t\t}, 0 );\n\t}\n\n\t/**\n\t * Tapping on background only should hide the overlay\n\t *\n\t */\n\tonClickOverlayContent() {\n\t\tthis.$el.find( '.cancel' ).trigger( 'click' );\n\t}\n\n\t/**\n\t * Hide the keyboard when scrolling starts (avoid weird situation when\n\t * user taps on an item, the keyboard hides and wrong item is clicked).\n\t *\n\t */\n\thideKeyboardOnScroll() {\n\t\tconst $input = this.getInput();\n\t\t$input.trigger( 'blur' );\n\t}\n\n\t/**\n\t * Handle the user clicking a result.\n\t *\n\t * @param {jQuery.Event} ev\n\t */\n\tonClickResult( ev ) {\n\t\tconst $link = this.$el.find( ev.currentTarget );\n\t\t// FIXME: ugly hack that removes search from browser history\n\t\t// when navigating to search results\n\t\tev.preventDefault();\n\t\tthis.router.back().then( () => {\n\t\t\t// T308288: Appends the current search id as a url param on clickthroughs\n\t\t\tif ( this.currentSearchId ) {\n\t\t\t\tconst clickUrl = new URL( location.href );\n\t\t\t\tclickUrl.searchParams.set( 'searchToken', this.currentSearchId );\n\t\t\t\tthis.router.navigateTo( document.title, {\n\t\t\t\t\tpath: clickUrl.toString(),\n\t\t\t\t\tuseReplaceState: true\n\t\t\t\t} );\n\t\t\t\tthis.currentSearchId = null;\n\t\t\t}\n\t\t\t// Router.navigate does not support changing href.\n\t\t\t// FIXME: Needs upstream change T189173\n\t\t\t// eslint-disable-next-line no-restricted-properties\n\t\t\twindow.location.href = $link.attr( 'href' );\n\t\t} );\n\t}\n\n\tgetInput() {\n\t\treturn this.$el.find( this.header ).find( 'input' );\n\t}\n\n\t/**\n\t * @inheritdoc\n\t */\n\tpostRender() {\n\t\tconst searchResults = new SearchResultsView( {\n\t\t\tsearchContentLabel: mw.msg( 'mobile-frontend-search-content' ),\n\t\t\tnoResultsMsg: mw.msg( 'mobile-frontend-search-no-results' ),\n\t\t\tsearchContentNoResultsMsg: mw.message( 'mobile-frontend-search-content-no-results' ).parse()\n\t\t} );\n\t\tlet timer;\n\n\t\tthis.$el.find( '.overlay-content' ).append( searchResults.$el );\n\t\tsuper.postRender();\n\n\t\t// FIXME: `$input` should not be set. Isolate to searchHeader function\n\t\tconst $input = this.getInput();\n\t\t// FIXME: `this.$searchContent` should not be set. Isolate to SearchResultsView class.\n\t\tthis.$searchContent = searchResults.$el.hide();\n\t\t// FIXME: `this.$resultContainer` should not be set. Isolate to SearchResultsView class.\n\t\tthis.$resultContainer = searchResults.$el.find( '.results-list-container' );\n\n\t\t// On iOS a touchstart event while the keyboard is open will result in a scroll\n\t\t// leading to an accidental click (T299846)\n\t\t// Stopping propagation when the input is focused will prevent scrolling while\n\t\t// the keyboard is collapsed.\n\t\tthis.$resultContainer[0].addEventListener( 'touchstart', ( ev ) => {\n\t\t\tif ( document.activeElement === $input[0] ) {\n\t\t\t\tev.stopPropagation();\n\t\t\t}\n\t\t} );\n\n\t\t/**\n\t\t * Hide the spinner and abort timed spinner shows.\n\t\t * FIXME: Given this manipulates SearchResultsView this should be moved into that class\n\t\t */\n\t\tconst clearSearch = () => {\n\t\t\tthis.$spinner.hide();\n\t\t\tclearTimeout( timer );\n\t\t};\n\n\t\t// Show a spinner on top of search results\n\t\t// FIXME: Given this manipulates SearchResultsView this should be moved into that class\n\t\tthis.$spinner = searchResults.$el.find( '.spinner-container' );\n\t\tthis.on( 'search-start', ( searchData ) => {\n\t\t\tif ( timer ) {\n\t\t\t\tclearSearch();\n\t\t\t}\n\t\t\ttimer = setTimeout( () => this.$spinner.show(),\n\t\t\t\tSEARCH_SPINNER_DELAY - searchData.delay );\n\t\t} );\n\t\tthis.on( 'search-results', clearSearch );\n\t}\n\n\t/**\n\t * Trigger a focus() event on search input in order to\n\t * bring up the virtual keyboard.\n\t *\n\t */\n\tshowKeyboard() {\n\t\tconst $input = this.getInput();\n\t\tconst len = $input.val().length;\n\t\t$input.trigger( 'focus' );\n\t\t// Cursor to the end of the input\n\t\tif ( $input[0].setSelectionRange ) {\n\t\t\t$input[0].setSelectionRange( len, len );\n\t\t}\n\t}\n\n\t/**\n\t * @inheritdoc\n\t */\n\tshow() {\n\t\t// Overlay#show defines the actual overlay visibility.\n\t\tsuper.show();\n\n\t\tthis.showKeyboard();\n\t}\n\n\t/**\n\t * Perform search and render results inside current view.\n\t * FIXME: Much of the logic for caching and pending queries inside this function should\n\t * actually live in SearchGateway, please move out.\n\t *\n\t * @param {string} query\n\t */\n\tperformSearch( query ) {\n\t\tconst $input = this.getInput();\n\t\tconst\n\t\t\tapi = this.api,\n\t\t\tdelay = this.gateway.isCached( query ) ? 0 : SEARCH_DELAY;\n\n\t\t// it seems the input event can be fired when virtual keyboard is closed\n\t\t// (Chrome for Android)\n\t\tif ( query !== this.lastQuery ) {\n\t\t\tif ( this._pendingQuery ) {\n\t\t\t\tthis._pendingQuery.abort();\n\t\t\t}\n\t\t\tclearTimeout( this.timer );\n\n\t\t\tif ( query.length ) {\n\t\t\t\tthis.timer = setTimeout( () => {\n\t\t\t\t\tconst xhr = this.gateway.search( query );\n\n\t\t\t\t\tthis._pendingQuery = xhr.then(\n\t\t\t\t\t\t( data ) => {\n\t\t\t\t\t\t\tif ( xhr.state() === 'resolved' && !data ) {\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tthis.currentSearchId = data.searchId;\n\n\t\t\t\t\t\t\t// FIXME: Given this manipulates SearchResultsView\n\t\t\t\t\t\t\t// this should be moved into that class\n\t\t\t\t\t\t\t// check if we're getting the rights response in case of out of\n\t\t\t\t\t\t\t// order responses (need to get the current value of the input)\n\t\t\t\t\t\t\tif ( data && data.query === $input.val() ) {\n\t\t\t\t\t\t\t\tthis.$el.toggleClass( 'no-results', data.results.length === 0 );\n\t\t\t\t\t\t\t\tthis.$searchContent\n\t\t\t\t\t\t\t\t\t.show()\n\t\t\t\t\t\t\t\t\t.find( 'p' )\n\t\t\t\t\t\t\t\t\t.hide()\n\t\t\t\t\t\t\t\t\t.filter( data.results.length ? '.with-results' : '.without-results' )\n\t\t\t\t\t\t\t\t\t.show();\n\n\t\t\t\t\t\t\t\t// eslint-disable-next-line no-new\n\t\t\t\t\t\t\t\tnew WatchstarPageList( {\n\t\t\t\t\t\t\t\t\tapi,\n\t\t\t\t\t\t\t\t\tfunnel: 'search',\n\t\t\t\t\t\t\t\t\tpages: data.results,\n\t\t\t\t\t\t\t\t\tel: this.$resultContainer\n\t\t\t\t\t\t\t\t} );\n\n\t\t\t\t\t\t\t\tthis.$results = this.$resultContainer.find( 'li' );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t).promise( {\n\t\t\t\t\t\tabort() {\n\t\t\t\t\t\t\txhr.abort();\n\t\t\t\t\t\t}\n\t\t\t\t\t} );\n\t\t\t\t}, delay );\n\t\t\t} else {\n\t\t\t\tthis.resetSearch();\n\t\t\t}\n\n\t\t\tthis.lastQuery = query;\n\t\t}\n\t}\n\n\t/**\n\t * Clear results\n\t *\n\t * @private\n\t */\n\tresetSearch() {\n\t\tthis.$el.find( '.overlay-content' ).children().hide();\n\t}\n}\n\nmodule.exports = SearchOverlay;\n","const View = require( '../View' ),\n\tIcon = require( '../Icon' ),\n\tAnchor = require( '../Anchor' ),\n\ticons = require( '../icons' ),\n\t$spinner = icons.spinner().$el,\n\tutil = require( '../util' );\n\n/**\n * Render search results.\n *\n * @param {Object} options\n * @param {string} options.searchContentLabel actionable label to tell the user they can \"search\n *  within pages rather than doing a full text search\n * @param {string} options.noResultsMsg shows when no results displayed\n * @param {string} options.searchContentNoResultsMsg alternative to options.searchContentLabel that\n * shows when no search results have been displayed.\n */\nclass SearchResultsView extends View {\n\t/** @inheritdoc */\n\tget isTemplateMode() {\n\t\treturn true;\n\t}\n\n\t/** @inheritdoc */\n\tget template() {\n\t\treturn util.template( `\n<div class=\"search-results-view\">\n\t<div class=\"search-content\">\n\t\t<div class=\"caption\">\n\t\t\t<p class=\"with-results\">{{searchContentLabel}}</p>\n\t\t\t<p class=\"without-results\">{{noResultsMsg}}</p>\n\t\t\t<p class=\"without-results\">{{{searchContentNoResultsMsg}}}</p>\n\t\t</div>\n\t</div>\n\t<div class=\"spinner-container position-fixed\"></div>\n\t<div class=\"results\">\n\t\t<div class=\"results-list-container\"></div>\n\t\t{{#feedback}}\n\t\t\t<div class=\"search-feedback\">\n\t\t\t\t{{prompt}}\n\t\t\t</div>\n\t\t{{/feedback}}\n\t</div>\n</div>`\n\t\t);\n\t}\n\n\t/** @inheritdoc */\n\tpreRender() {\n\t\tconst feedbackLink = mw.config.get( 'wgCirrusSearchFeedbackLink' );\n\t\tif ( feedbackLink ) {\n\t\t\tthis.options.feedback = {\n\t\t\t\tprompt: mw.msg( 'mobile-frontend-search-feedback-prompt' ) };\n\t\t}\n\t}\n\n\t/** @inheritdoc */\n\tpostRender( options ) {\n\t\tconst feedbackLink = mw.config.get( 'wgCirrusSearchFeedbackLink' );\n\t\tsuper.postRender( options );\n\t\tthis.$el.find( '.search-content' ).prepend(\n\t\t\tnew Icon( { icon: 'articlesSearch' } ).$el\n\t\t);\n\t\tthis.$el.find( '.spinner-container' ).append( $spinner );\n\t\tif ( feedbackLink ) {\n\t\t\tthis.$el.find( '.search-feedback' ).append(\n\t\t\t\tnew Anchor( {\n\t\t\t\t\tlabel: mw.msg( 'mobile-frontend-search-feedback-link-text' ),\n\t\t\t\t\thref: feedbackLink\n\t\t\t\t} ).$el\n\t\t\t);\n\t\t}\n\t}\n}\n\nmodule.exports = SearchResultsView;\n","const formHeader = require( '../headers' ).formHeader,\n\tSearchHeaderView = require( './SearchHeaderView' ),\n\ticons = require( '../icons' );\n\n/**\n * Generate a search header\n *\n * @param {string} placeholderMsg\n * @param {string} action\n * @param {Function} onInput\n * @param {string} defaultSearchPage\n * @param {string} autocapitalize\n * @return {jQuery.Element}\n */\nmodule.exports = function searchHeader( placeholderMsg, action, onInput, defaultSearchPage, autocapitalize ) {\n\treturn formHeader(\n\t\tnew SearchHeaderView( {\n\t\t\tplaceholderMsg,\n\t\t\tautocapitalize,\n\t\t\taction,\n\t\t\tonInput,\n\t\t\tdefaultSearchPage\n\t\t} ),\n\t\t[\n\t\t\ticons.cancel()\n\t\t],\n\t\tfalse\n\t);\n};\n","const units = [ 'seconds', 'minutes', 'hours', 'days', 'months', 'years' ],\n\tutil = require( './util' ),\n\tlimits = [ 1, 60, 3600, 86400, 2592000, 31536000 ];\n\n/**\n * Calculate the correct unit of timestamp\n *\n * @memberof module:mobile.startup/time\n * @instance\n * @param {number} timestampDelta\n * @return {{value: number, unit: string}}\n */\nfunction timeAgo( timestampDelta ) {\n\tlet i = 0;\n\twhile ( i < limits.length && timestampDelta > limits[i + 1] ) {\n\t\t++i;\n\t}\n\treturn {\n\t\tvalue: Math.round( timestampDelta / limits[i] ),\n\t\tunit: units[i]\n\t};\n}\n\n/**\n * Calculate the correct unit of timestamp delta\n *\n * @memberof module:mobile.startup/time\n * @param {number} timestamp\n * @return {{value: number, unit: string}}\n */\nfunction getTimeAgoDelta( timestamp ) {\n\tconst currentTimestamp = Math.round( Date.now() / 1000 );\n\n\treturn timeAgo( currentTimestamp - timestamp );\n}\n\n/**\n * Whether timestamp delta is less than a day old\n *\n * @instance\n * @memberof module:mobile.startup/time\n * @param {{value: number, unit: string}} delta Object of timestamp and its label\n * @return {boolean}\n */\nfunction isRecent( delta ) {\n\treturn [ 'seconds', 'minutes', 'hours' ].indexOf( delta.unit ) > -1;\n}\n\n/**\n * Is delta less than 10 seconds?\n *\n * @instance\n * @memberof module:mobile.startup/time\n * @param {{value: number, unit: string}} delta Object of timestamp and its label\n * @return {boolean}\n */\nfunction isNow( delta ) {\n\treturn delta.unit === 'seconds' && delta.value < 10;\n}\n\n/**\n * Return a message relating to the last modified relative time.\n *\n * @instance\n * @memberof module:mobile.startup/time\n * @param {number} ts timestamp\n * @param {string} username of the last user to modify the page\n * @param {string} gender of the last user to modify the page\n * @param {string} historyUrl url to the history page for the message (deprecated)\n * @return {string}\n */\nfunction getLastModifiedMessage( ts, username, gender, historyUrl ) {\n\tconst linkAll = typeof historyUrl === 'undefined',\n\t\tkeys = {\n\t\t\tseconds: 'mobile-frontend-last-modified-with-user-seconds',\n\t\t\tminutes: 'mobile-frontend-last-modified-with-user-minutes',\n\t\t\thours: 'mobile-frontend-last-modified-with-user-hours',\n\t\t\tdays: 'mobile-frontend-last-modified-with-user-days',\n\t\t\tmonths: 'mobile-frontend-last-modified-with-user-months',\n\t\t\tyears: 'mobile-frontend-last-modified-with-user-years'\n\t\t},\n\t\targs = [];\n\n\tgender = gender || 'unknown';\n\n\tconst delta = getTimeAgoDelta( ts );\n\tif ( isNow( delta ) ) {\n\t\targs.push( 'mobile-frontend-last-modified-with-user-just-now', gender, username );\n\t} else {\n\t\targs.push( keys[ delta.unit ], gender, username,\n\t\t\tmw.language.convertNumber( delta.value )\n\t\t);\n\t}\n\n\tconst lastEditedElement = linkAll ?\n\t\tutil.parseHTML( '<strong>' ).attr( 'class', 'last-modified-text-accent' ) :\n\t\tutil.parseHTML( '<a>' ).attr( 'href', historyUrl || '#' );\n\tconst usernameElement = linkAll ?\n\t\tutil.parseHTML( '<span>' ).attr( 'class', 'last-modified-text-accent' ) :\n\t\tutil.parseHTML( '<a>' ).attr( 'href', mw.util.getUrl( 'User:' + username ) );\n\n\targs.push(\n\t\tlastEditedElement,\n\t\t// Abuse PLURAL support to determine if the user is anonymous or not\n\t\tmw.language.convertNumber( username ? 1 : 0 ),\n\t\t// Our abuse of PLURAL support means we have to pass the relative URL\n\t\t// rather than construct it from a wikilink\n\t\tusername ? usernameElement : ''\n\t);\n\n\treturn mw.message.apply( this, args ).parse();\n}\n\n/**\n * Return a message relating to the registration date of the user\n *\n * @instance\n * @memberof module:mobile.startup/time\n * @param {string} ts timestamp\n * @param {string} [gender] of the last user editing this page\n * @return {string}\n */\nfunction getRegistrationMessage( ts, gender ) {\n\tconst keys = {\n\t\tseconds: 'mobile-frontend-joined-seconds',\n\t\tminutes: 'mobile-frontend-joined-minutes',\n\t\thours: 'mobile-frontend-joined-hours',\n\t\tdays: 'mobile-frontend-joined-days',\n\t\tmonths: 'mobile-frontend-joined-months',\n\t\tyears: 'mobile-frontend-joined-years'\n\t};\n\n\tconst args = [];\n\n\tgender = gender || 'unknown';\n\n\tconst delta = getTimeAgoDelta( parseInt( ts, 10 ) );\n\tif ( isNow( delta ) ) {\n\t\targs.push( 'mobile-frontend-joined-just-now', gender );\n\t} else {\n\t\targs.push( keys[ delta.unit ], gender, mw.language.convertNumber( delta.value ) );\n\t}\n\tconst html = mw.message.apply( this, args ).parse();\n\treturn html;\n}\n\n/**\n * Utility library for relative time.\n *\n * @exports module:mobile.startup/time\n */\nmodule.exports = {\n\tgetLastModifiedMessage,\n\tgetRegistrationMessage,\n\ttimeAgo,\n\tgetTimeAgoDelta,\n\tisNow,\n\tisRecent\n};\n"],"names":["util","actionParams","module","exports","constructor","api","this","getLanguages","get","meta","liprop","then","resp","filteredLanguages","Object","keys","query","languageinfo","forEach","key","language","code","toLowerCase","bcp47","autonym","push","Deferred","reject","languages","map","data","url","lang","langname","name","title","View","props","super","isTemplateMode","defaults","template","Section","options","tag","level","line","text","hasReferences","id","anchor","subsections","section","undefined","navigator","userLanguage","browserLanguage","systemLanguage","m","getDeviceLanguage","Overlay","promisedView","loadLanguageInfoSearcher","languageInfo","showSuggestedLanguages","mw","loader","using","require","variants","deviceLanguage","languageInfoOverlay","make","heading","msg","className","test","MessageBox","currentPageHTMLParser","loadLanguageSearcher","config","onOpen","searcher","hook","fire","type","languageOverlay","header","icons","headers","cancel","Promise","all","ImageCarousel","time","LanguageInfo","currentPage","Drawer","CtaDrawer","lazyImageLoader","PageHTMLParser","showOnPageReload","OverlayManager","references","search","SearchOverlay","SearchGateway","Skin","mediaViewer","overlay","amcOutreach","Icon","IconButton","Button","overlayHeader","class","getOverlayManager","getSingleton","spinner","cancelIcon","loadAllImagesInPage","loadImages","queryPlaceholders","document","getElementById","notifyOnPageReload","license","getLicenseMsg","showSuggestedLanguage","promise","view","$el","append","newView","replaceWith","errorView","ReferencesGateway","getReference","page","pageHTMLParser","ERROR_NOT_EXIST","ERROR_OTHER","arguments","EXTERNAL_LINK_CLASS","getReferenceFromContainer","$container","result","find","escapeSelector","length","$parent","$ol","closest","isSubref","hasClass","parent","addClass","resolve","getReferenceHtml","parentText","$reference","children","first","html","hash","percentDecodeFragment","slice","ReferencesHtmlScraperGateway","makeOnNestedReferenceClickHandler","onNestedReferenceClick","ev","target","currentTarget","querySelector","getAttribute","textContent","referenceDrawer","errorIcon","error","isSmall","mainRef","mainRefHtml","parseHTML","subRefHtml","extend","showCollapseIcon","events","preventDefault","icon","additionalClassNames","showReference","refNumber","gateway","onShowNestedReference","reference","drawer","href","nestedDrawer","log","warn","body","appendChild","hide","show","err","pageJSONParser","extendSearchParams","searchCache","generator","searchNamespace","getApiData","prefix","redirects","pilimit","pithumbsize","tiny","_createSearchRegEx","str","replace","RegExp","_highlightSearchTerm","label","term","trim","_getPage","pageInfo","parse","displayTitle","displaytext","index","_processData","results","pages","sort","a","b","scriptPath","isCached","xhr","request","jqXHR","searchId","getResponseHeader","abort","Boolean","autocapitalize","onInput","value","clearIcon","postRender","tagName","size","click","val","trigger","attr","searchHeader","SearchResultsView","WatchstarPageList","params","placeholderMsg","action","performSearch","defaultSearchPage","headerChrome","isBorderBox","stopPropagation","gatewayClass","router","currentSearchId","onClickSearchContent","$form","parentNode","appendTo","setTimeout","onClickOverlayContent","hideKeyboardOnScroll","getInput","onClickResult","$link","back","clickUrl","URL","location","searchParams","set","navigateTo","path","toString","useReplaceState","window","searchResults","searchContentLabel","noResultsMsg","searchContentNoResultsMsg","message","timer","$input","$searchContent","$resultContainer","addEventListener","activeElement","clearSearch","$spinner","clearTimeout","on","searchData","delay","showKeyboard","len","setSelectionRange","lastQuery","_pendingQuery","state","toggleClass","filter","funnel","el","$results","resetSearch","Anchor","preRender","feedback","prompt","feedbackLink","prepend","formHeader","SearchHeaderView","units","limits","timeAgo","timestampDelta","i","Math","round","unit","getTimeAgoDelta","timestamp","Date","now","isNow","delta","getLastModifiedMessage","ts","username","gender","historyUrl","linkAll","args","seconds","minutes","hours","days","months","years","convertNumber","lastEditedElement","usernameElement","getUrl","apply","getRegistrationMessage","parseInt","isRecent","indexOf"],"sourceRoot":""}