{"version":3,"sources":["webpack://mfModules.[name]/./node_modules/hogan.js/lib/compiler.js","webpack://mfModules.[name]/./node_modules/hogan.js/lib/hogan.js","webpack://mfModules.[name]/./node_modules/hogan.js/lib/template.js","webpack://mfModules.[name]/(webpack)/buildin/global.js","webpack://mfModules.[name]/./src/mobile.categories.overlays/CategoryGateway.js","webpack://mfModules.[name]/./src/mobile.editor.overlay/AbuseFilterOverlay.js","webpack://mfModules.[name]/./src/mobile.editor.overlay/AbuseFilterPanel.js","webpack://mfModules.[name]/./src/mobile.editor.overlay/BlockMessage.js","webpack://mfModules.[name]/./src/mobile.editor.overlay/EditorGateway.js","webpack://mfModules.[name]/./src/mobile.editor.overlay/EditorOverlay.js","webpack://mfModules.[name]/./src/mobile.editor.overlay/EditorOverlayBase.js","webpack://mfModules.[name]/./src/mobile.editor.overlay/VisualEditorOverlay.js","webpack://mfModules.[name]/./src/mobile.editor.overlay/parseSaveError.js","webpack://mfModules.[name]/./src/mobile.editor.overlay/saveFailureMessage.js","webpack://mfModules.[name]/./src/mobile.languages.structured/LanguageSearcher.js","webpack://mfModules.[name]/./src/mobile.languages.structured/rtlLanguages.js","webpack://mfModules.[name]/./src/mobile.languages.structured/util.js","webpack://mfModules.[name]/./src/mobile.mediaViewer/ImageCarousel.js","webpack://mfModules.[name]/./src/mobile.mediaViewer/ImageGateway.js","webpack://mfModules.[name]/./src/mobile.mediaViewer/LoadErrorMessage.js","webpack://mfModules.[name]/./src/mobile.special.nearby.scripts/Nearby.js","webpack://mfModules.[name]/./src/mobile.special.nearby.scripts/NearbyGateway.js","webpack://mfModules.[name]/./src/mobile.special.uploads.scripts/PhotoListGateway.js","webpack://mfModules.[name]/./src/mobile.special.watchlist.scripts/WatchList.js","webpack://mfModules.[name]/./src/mobile.special.watchlist.scripts/WatchListGateway.js","webpack://mfModules.[name]/./src/mobile.startup/Anchor.js","webpack://mfModules.[name]/./src/mobile.startup/Browser.js","webpack://mfModules.[name]/./src/mobile.startup/Button.js","webpack://mfModules.[name]/./src/mobile.startup/CtaDrawer.js","webpack://mfModules.[name]/./src/mobile.startup/Drawer.js","webpack://mfModules.[name]/./src/mobile.startup/Icon.js","webpack://mfModules.[name]/./src/mobile.startup/MessageBox.js","webpack://mfModules.[name]/./src/mobile.startup/Overlay.js","webpack://mfModules.[name]/./src/mobile.startup/OverlayManager.js","webpack://mfModules.[name]/./src/mobile.startup/Page.js","webpack://mfModules.[name]/./src/mobile.startup/PageGateway.js","webpack://mfModules.[name]/./src/mobile.startup/PageList.js","webpack://mfModules.[name]/./src/mobile.startup/Panel.js","webpack://mfModules.[name]/./src/mobile.startup/ScrollEndEventEmitter.js","webpack://mfModules.[name]/./src/mobile.startup/Section.js","webpack://mfModules.[name]/./src/mobile.startup/Thumbnail.js","webpack://mfModules.[name]/./src/mobile.startup/Toggler.js","webpack://mfModules.[name]/./src/mobile.startup/View.js","webpack://mfModules.[name]/./src/mobile.startup/actionParams.js","webpack://mfModules.[name]/./src/mobile.startup/cache.js","webpack://mfModules.[name]/./src/mobile.startup/context.js","webpack://mfModules.[name]/./src/mobile.startup/extendSearchParams.js","webpack://mfModules.[name]/./src/mobile.startup/icons.js","webpack://mfModules.[name]/./src/mobile.startup/languageOverlay/getDeviceLanguage.js","webpack://mfModules.[name]/./src/mobile.startup/languageOverlay/languageOverlay.js","webpack://mfModules.[name]/./src/mobile.startup/lazyImages/lazyImageLoader.js","webpack://mfModules.[name]/./src/mobile.startup/lazyReferencesLoader.js","webpack://mfModules.[name]/./src/mobile.startup/loadingOverlay.js","webpack://mfModules.[name]/./src/mobile.startup/mfExtend.js","webpack://mfModules.[name]/./src/mobile.startup/moduleLoader.js","webpack://mfModules.[name]/./src/mobile.startup/moduleLoaderSingleton.js","webpack://mfModules.[name]/./src/mobile.startup/promisedView.js","webpack://mfModules.[name]/./src/mobile.startup/references/ReferencesDrawer.js","webpack://mfModules.[name]/./src/mobile.startup/references/ReferencesGateway.js","webpack://mfModules.[name]/./src/mobile.startup/references/ReferencesHtmlScraperGateway.js","webpack://mfModules.[name]/./src/mobile.startup/references/ReferencesMobileViewGateway.js","webpack://mfModules.[name]/./src/mobile.startup/rlModuleLoader.js","webpack://mfModules.[name]/./src/mobile.startup/search/MobileWebSearchLogger.js","webpack://mfModules.[name]/./src/mobile.startup/search/SearchGateway.js","webpack://mfModules.[name]/./src/mobile.startup/talk/overlay.js","webpack://mfModules.[name]/./src/mobile.startup/time.js","webpack://mfModules.[name]/./src/mobile.startup/toast.js","webpack://mfModules.[name]/./src/mobile.startup/util.js","webpack://mfModules.[name]/./src/mobile.startup/watchstar/Watchstar.js","webpack://mfModules.[name]/./src/mobile.startup/watchstar/WatchstarGateway.js","webpack://mfModules.[name]/./src/mobile.startup/watchstar/WatchstarPageList.js","webpack://mfModules.[name]/./src/mobile.talk.overlays/AddTopicForm.js","webpack://mfModules.[name]/./src/mobile.talk.overlays/TalkSectionAddOverlay.js","webpack://mfModules.[name]/./src/mobile.talk.overlays/TalkSectionOverlay.js","webpack://mfModules.[name]/./src/mobile.talk.overlays/autosign.js","webpack://mfModules.[name]/./src/mobile.talk.overlays/makeAddTopicForm.js","webpack://mfModules.[name]/./src/mobile.talk.overlays/talkBoard.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.categories.overlays/CategoryGateway.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.editor.overlay/EditorGateway.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.editor.overlay/EditorOverlay.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.languages.structured/LanguageSearcher.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.languages.structured/util.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.mediaViewer/ImageCarousel.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.mediaViewer/ImageGateway.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.special.nearby.scripts/Nearby.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.special.nearby.scripts/NearbyGateway.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.special.uploads.scripts/PhotoListGateway.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.special.watchlist.scripts/WatchList.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.special.watchlist.scripts/WatchListGateway.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.startup/Browser.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.startup/Button.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.startup/CtaDrawer.test.html.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.startup/CtaDrawer.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.startup/Drawer.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.startup/Overlay.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.startup/OverlayManager.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.startup/Page.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.startup/PageGateway.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.startup/Panel.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.startup/ScrollEndEventEmitter.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.startup/Section.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.startup/Toggler.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.startup/View.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.startup/cache.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.startup/context.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.startup/extendSearchParams.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.startup/icons.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.startup/languageOverlay/getDeviceLanguage.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.startup/languageOverlay/languageOverlay.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.startup/lazyImages/lazyImageLoader.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.startup/lazyReferencesLoader.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.startup/mfExtend.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.startup/moduleLoader.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.startup/promisedView.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.startup/references/ReferencesDrawer.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.startup/references/ReferencesHtmlScraperGateway.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.startup/references/ReferencesMobileViewGateway.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.startup/rlModuleLoader.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.startup/search/MobileWebSearchLogger.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.startup/search/SearchGateway.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.startup/talk/overlay.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.startup/time.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.startup/util.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.startup/watchstar/Watchstar.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.startup/watchstar/WatchstarGateway.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.startup/watchstar/WatchstarPageList.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.talk.overlays/AddTopicForm.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.talk.overlays/TalkSectionAddOverlay.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.talk.overlays/TalkSectionOverlay.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.talk.overlays/autosign.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.talk.overlays/makeAddTopicForm.test.js","webpack://mfModules.[name]/./tests/node-qunit/mobile.talk.overlays/talkBoard.test.js","webpack://mfModules.[name]/./tests/node-qunit/utils/PageGateway.responses.js","webpack://mfModules.[name]/./tests/node-qunit/utils/PageInputs.html.js","webpack://mfModules.[name]/./tests/node-qunit/utils/dom.js","webpack://mfModules.[name]/./tests/node-qunit/utils/jQuery.js","webpack://mfModules.[name]/./tests/node-qunit/utils/mw.js","webpack://mfModules.[name]/./tests/node-qunit/utils/oo.js","webpack://mfModules.[name]/external \"jquery\"","webpack://mfModules.[name]/external \"jsdom\"","webpack://mfModules.[name]/external \"oojs\"","webpack://mfModules.[name]/external \"sinon\""],"names":["Hogan","rIsWhitespace","rQuot","rNewline","rCr","rSlash","tagTypes","#","^","/","!",">","<","=","_v","{","&","cleanTripleStache","token","n","substr","length","substring","trim","s","replace","tagChange","tag","text","index","charAt","i","l","isOpener","tags","o","isCloser","close","open","c","esc","chooseMethod","indexOf","walk","tree","code","section","nodes","end","otag","ctag","invertedSection","partial","tripleStache","variable","undefined","id","method","start","tok","indent","scan","delimiters","len","state","tagType","buf","tokens","seenTag","lineStart","addBuf","push","String","filterLine","haveSeenTag","noNewLine","isAllWhitespace","j","match","lineIsWhitespace","next","toString","splice","changeDelimiters","closeIndex","split","generate","options","asString","Template","Function","parse","buildTree","kind","stack","customTags","instructions","opener","shift","Error","pop","sectionTags","cache","compile","key","t","this","exports","__webpack_require__","module","useArrayBuffer","renderFunc","compiler","r","prototype","context","partials","v","str","coerceToString","hChars","test","rAmp","rLt","rGt","rApos","render","ri","rp","name","rs","tail","isArray","val","ctx","inverted","pass","ls","d","returnFound","names","f","cx","lv","found","ho","call","b","fl","result","Array","a","Object","g","eval","e","window","actionParams","require","util","SearchGateway","CategoryGateway","parent","apply","arguments","continueParams","canContinue","searchNamespace","save","title","categories","api","postWithToken","action","appendtext","summary","mw","msg","getCategories","params","self","extend","prop","titles","clprop","cllimit","get","then","data","continue","OO","inheritClass","Button","mfExtend","Overlay","AbuseFilterOverlay","props","className","defaults","confirmButton","additionalClassNames","progressive","templatePartials","button","template","content","postRender","$el","find","attr","View","AbuseFilterPanel","isDisallowed","overlayManager","readMoreMsg","show","type","message","add","removeClass","hide","addClass","Drawer","Icon","BlockMessage","stopHandIcon","userIcon","tagName","okButton","label","createDetailsAnchorHref","getUrl","wpTarget","blockId","createDetailsAnchorLabel","createTitle","reasonHeader","creatorHeader","user","gender","expiryHeader","icon","parseSaveError","EditorGateway","sectionId","oldId","isNewPage","hasChanged","getBlockInfo","pageObj","blockedError","actions","edit","some","error","blockinfo","loader","load","getContent","resolve","Deferred","userinfo","meta","rvprop","intestactions","intestactionsdetail","uiprop","rvstartid","isNumeric","rvsection","resp","revision","reject","query","pages","missing","revisions","timestamp","originalContent","setContent","setPrependText","prependtext","apiOptions","captchaid","captchaId","captchaword","captchaWord","basetimestamp","starttimestamp","saveContent","abortPreview","_pending","abort","getPreview","request","sectionLine","sectionpreview","pst","mobileformat","post","sections","anchor","line","promise","EditorOverlayBase","Section","saveFailureMessage","VisualEditorOverlay","MessageBox","EditorOverlay","isFirefox","navigator","userAgent","gateway","readOnly","isVisualEditorEnabled","editSwitcher","editingMsg","isVisualEditor","previewingMsg","events","input .wikitext-editor","editor","ns","config","namespaces","onInputWikitextEditor","onClickContinue","ev","isAnon","target","hasClass","_showEditorAfterWarning","onClickBack","_hidePreview","$anonWarning","using","switchToolbar","toolFactory","ui","ToolFactory","toolGroupFactory","ToolGroupFactory","register","libs","ve","MWEditModeVisualTool","MWEditModeSourceTool","Toolbar","classes","on","mode","confirm","onStageChanges","_switchToVisualEditor","setup","include","html","$element","emit","$preview","$content","prepend","_renderAnonWarning","$anonHiddenButtons","hideSpinner","abuseFilterPanel","appendTo","_resizeEditor","bind","_loadContent","returnto","returnTo","returntoquery","warning","queryParams","signupParams","signupQueryParams","anonymousEditorActions","block","href","append","map","showSpinner","hideSpinnerAndShowPreview","scrollTop","getDocument","mainpage","parsedText","parsedSectionLine","parseHTML","el","scrollTo","showHidden","container","$scrollContainer","Element","static","getClosestScrollableContainer","css","height","_parseBlockInfo","blockInfo","expiry","reason","moment","blockpartial","creator","blockedby","url","duration","blockid","blockexpiry","format","to","blockreason","wikitext","parser","ast","jqueryMsg","wikiTextToAst","emitter","jqueryMsgParse","escape","escaped","toggle","reportError","log","mechanism","storage","set","targetLoader","addPlugin","loadModules","switched","switching","replaceCurrent","_showAbuseFilter","onSaveBegin","confirmAborted","location","onSaveComplete","onSaveFailure","heading","details","handleCaptcha","PageGateway","toast","mwUser","EditVeTool","toolGroup","super","isBorderBox","click .back","click .continue","click .submit","placeholder","summaryRequestMsg","pageGateway","editCount","isNewEditor","sessionId","allowCloseWindow","confirmCloseWindow","namespace","Tool","group","onSelect","onUpdateState","hasToolbar","continueMsg","cancelMsg","closeMsg","summaryMsg","waitMsg","waitIcon","toHtmlString","captchaMsg","captchaTryAgainMsg","switchMsg","confirmMsg","licenseMsg","editHeader","previewHeader","saveHeader","track","editor_interface","editing_session_id","confirmSave","$window","getWindow","saved","invalidatePage","showOnPageReload","hash","off","reload","editconflict","wasdeleted","abusefilter-disallowed","captcha","spamprotectiontext","titleblacklist-forbidden-edit","errorNotice","$errorNoticeContainer","hideErrorNotice","empty","skipPreview","nextStep","saveMsg","hook","fire","onClickSubmit","windowManager","getWindowManager","addWindows","widgets","AbandonEditDialog","openWindow","closed","release","edited","shouldConfirmLeave","force","$input","captchaShown","setTimeout","mime","detach","question","applyHeaderOptions","isVE","destroyTarget","destroy","init","targetFactory","create","once","dataPromise","overlay","retval","switchToEditor","switchToSourceEditor","getSurface","getModel","hasBeenModified","readonlyreason","info","langUtil","LanguageSearcher","languages","getStructuredLanguages","variants","getFrequentlyUsedLanguages","deviceLanguage","click a","input .search","inputPlaceholder","allLanguagesHeader","toLocaleUpperCase","suggestedLanguagesHeader","allLanguages","all","allLanguagesCount","suggestedLanguages","suggested","suggestedLanguagesCount","$siteLinksList","$languageItems","$subheaders","onLinkClick","lang","currentTarget","saveLanguageUsageCount","onSearchInput","filterLanguages","toLowerCase","filteredList","forEach","language","langname","autonym","variant","join","mfUtils","rtlLanguages","getDir","dir","frequentlyUsedLanguages","hasOwn","hasOwnProperty","maxFrequency","minFrequency","missingDir","addLangDir","parentLanguage","deviceLanguagesWithVariants","slice","getDeviceLanguageOrParent","keys","frequency","sort","toLocaleLowerCase","warn","languageMap","JSON","saveFrequentlyUsedLanguages","stringify","languageCode","count","icons","detailsButton","slideLeftButton","rotation","slideRightButton","LoadErrorMessage","ImageGateway","router","ImageCarousel","eventBus","click .image-wrapper","click .slider-button","hideOnExitClick","licenseLinkMsg","thumbnails","onSlide","newImageCarousel","nextThumbnail","closest","filename","navigateTo","path","useReplaceState","replaceWith","preRender","thumbnail","getFileName","caption","getDescription","galleryOffset","_enableArrowImages","thumbs","lastThumb","nextThumb","offset","_disableArrowImages","remove","_handleRetry","$img","$spinner","spinner","showLoadFailMsg","hasLoadError","retryPath","getPath","prependTo","addImageLoadClass","$details","getThumb","author","descriptionurl","thumbWidth","thumbwidth","thumbHeight","thumbheight","imgRatio","document","thumburl","_positionImage","extmetadata","LicenseShortName","value","Artist","adjustDetails","onToggleDetails","detailsHeight","windowWidth","windowHeight","windowRatio","is","outerHeight","width","sizeBuckets","findSizeBucket","size","_cache","cachedThumb","imageSizeMultiplier","devicePixelRatio","iiprop","iiurlwidth","iiurlheight","imageinfo","_findSizeBucket","click .load-fail-msg-link a","isTemplateMode","msgToUser","retryTxt","onRetry","NearbyGateway","WatchstarPageList","Nearby","_super","range","source","nearbyApi","errorType","errorOptions","_errorOptions","onItemClick","errorMessages","hasHeading","http","incompatible","pageList","messageBox","_find","pagesSuccess","_isLoading","pagesError","latitude","longitude","getPages","exclude","pageTitle","getPagesAroundPage","_postRenderLinks","each","refresh","Page","extendSearchParams","_distanceMessage","Math","ceil","convertNumber","toFixed","coords","_search","ggscoord","page","ggspage","requestParams","colimit","generator","ggsradius","ggsnamespace","ggslimit","codistancefrompoint","codistancefrompage","ajax","p","newFromJSON","coordinates","dist","lat","lon","proximity","filter","PhotoListGateway","username","category","limit","getWidth","small","_getImageDataFromPage","img","description","descriptionUrl","getQuery","gaiuser","gaisort","gaidir","gailimit","gcmtitle","gcmtype","gcmdir","gcmlimit","origin","getPhotos","photos","PageList","ScrollEndEventEmitter","WatchListGateway","WatchList","lastTitle","scrollEndEventEmitter","EVENT_SCROLL_END","_loadPages","getLastTitle","disable","setElement","$items","statuses","queryUnitializedItems","parsePagesFromItems","reduce","renderItems","enable","loadWatchlist","appendPage","templateOptions","wikidataDescription","item","gwrcontinue","shouldSkipFirstTitle","gwrnamespace","gwrlimit","apiUrl","parseData","p1","p2","Anchor","destructive","browser","memoize","memoized","cacheId","Date","now","random","Browser","ua","$container","isIos","version","ios","isWideScreen","parseInt","innerWidth","innerHeight","supportsAnimations","elemStyle","createElement","style","supportsProperty","property","toUpperCase","supportsTouchEvents","supportsGeoLocation","getSingleton","$html","quiet","CtaDrawer","progressiveButton","actionAnchor","redirectParams","redirectURL","signUpParams","Panel","click","collapseIcon","appendToElement","closeOnScroll","docReady","onShowDrawer","onHideDrawer","stopPropagation","one","minHideDelay","hasText","modifier","setRotationClass","_rotationClass","glyphPrefix","isSmall","base","getClassName","getGlyphClassName","click .cancel, .confirm, .initial-header .back","fullScreen","header","headerActions","cancelButton","cancel","backButton","headerChrome","closeOnContentTap","hasActions","headerButtons","$overlayContent","component","onExitClick","exit","EVENT_EXIT","preventDefault","onBeforeExit","pageYOffset","pageXOffset","make","view","OverlayManager","_checkRoute","entries","hideCurrent","attachHideEvent","_onHideOverlay","back","_attachOverlay","parents","appendChild","_show","_hideOverlay","_processMatch","factoryResult","current","m","_matchRoute","entry","route","previous","getNext","factory","unshift","body","HTML","time","Thumbnail","HEADING_SELECTOR","BLACKLISTED_THUMBNAIL_CLASS_SELECTORS","titleObj","displayTitle","isMissing","languageUrl","getDisplayTitle","isLandscape","namespaceNumber","protection","isMainPage","inNamespace","findSectionHeadingByIndex","sectionIndex","eq","findChildInSectionLead","selector","$heading","$nextHeading","$lead","headingSelector","withNestedChildren","$matchingNodes","addBack","getLeadSectionElement","children","prevAll","nextAll","nextUntil","isWikiText","isWatched","getRevisionId","revId","getTitle","getId","getNamespaceId","args","isTalkPage","_sectionLookup","sectionData","getThumbnails","blacklistSelector","_thumbs","not","$a","$lazyImage","valid","legacyMatch","RegExp","decodeURIComponent","getSection","getSections","getRedLinks","thumb","pageprops","displaytitle","terms","lastModified","getLastModifiedMessage","getTime","pageid","sectionTemplate","transformSections","lastSection","existingSectionLevels","level","collapseLevel","min","subsections","assignToParent","listOfSections","child","getPage","pageData","endpoint","leadOnly","dataType","redirect","noheadings","sectionprop","resolveObj","mv","mobileview","lastmodified","lastmodifiedby","lead","historyUrl","lastModifiedTimestamp","languageCount","languagecount","hasVariants","hasvariants","lastModifiedUserName","lastModifiedUserGender","_getLanguageVariantsFromApiResponse","generalData","general","variantPath","variantarticlepath","getPageLanguages","siprop","lllimit","llprop","llinlanguagecode","langlinks","_getAPIResponseFromHTML","$span","getSectionsFromHTML","renderPageImages","click .cancel","onCancel","isVisible","threshold","EventEmitter","mixinClass","_bindScroll","_scrollHandler","_onScroll","_unbindScroll","enabled","scrollNearEnd","scrollBottom","endPosition","top","hasReferences","siblings","escapeHash","arrowOptions","Toggler","_enable","prefix","isClosed","getExpandedSections","expandedSections","saveExpandedSections","expandStoredSections","toggler","$sectionHeading","$headline","cleanObsoleteStoredSections","floor","indicator","wasExpanded","toggleClass","aria-pressed","aria-expanded","expanded","isReferenceSection","Boolean","headline","isSectionOpen","storeSectionToggleState","reveal","$target","prev","expandSections","$link","collapseSectionsByDefault","checkHash","$indicator","tabindex","aria-haspopup","aria-controls","which","enableKeyboardActions","internalRedirect","internalRedirectHash","checkInternalRedirectAndHash","_getExpandedSections","_expandStoredSections","_cleanObsoleteStoredSections","delegateEventSplitter","idCounter","initialize","cid","uniqueId","$","_postInitialize","undelegateEvents","skipTemplateRender","delegateEvents","delegate","eventName","listener","undelegate","$child","defaultParams","formatversion","otherParams","scriptPath","MemoryCache","NoCache","getMode","feature","displayWikibaseDescriptions","concat","CANCEL_GLYPH","glyph","watchIcon","watchedIcon","userLanguage","browserLanguage","systemLanguage","getDeviceLanguage","promisedView","loadLanguageSearcher","languageOverlay","placeholderClass","queryPlaceholders","root","getElementsByClassName","loadImages","placeholders","Promise","loadImage","deferred","dataset","image","Image","class","alt","cssText","addEventListener","classList","parentNode","replaceChild","src","srcset","lazyImageLoader","getSectionId","hSelector","$parent","loadReferences","getReferencesLists","lastId","refListIndex","$placeholder","getReferencesList","refListElements","loadImagesAndSetData","noHeader","Child","ParentOrPrototype","initClass","ModuleLoader","_register","registry","localRequire","define","obj","deprecate","deprecatedId","replacement","newView","errorView","ReferencesGateway","ReferencesDrawer","click sup a","citation","errorClassName","onShow","onHide","showReference","refNumber","drawer","getReference","reference","err","ERROR_NOT_EXIST","showNestedReference","$dest","ERROR_OTHER","ReferencesHtmlScraperGateway","getReferenceFromContainer","escapeSelector","referencesMobileViewGateway","ReferencesMobileViewGateway","cachedReferencesSections","$section","headingId","Api","loadingOverlay","newLoadingOverlay","loadModule","delegateHide","showLoadingOverlay","hideOverlayIfNeeded","MobileWebSearchLogger","userSessionToken","searchSessionToken","_newUserSession","generateRandomSessionId","_newSearchSession","searchSessionCreatedAt","onSearchShow","onSearchStart","timeOffsetSinceStart","onSearchResults","event","resultSetType","numberOfResults","results","timeToDisplayResults","onSearchResultClick","clickIndex","resultIndex","searchOverlay","logger","searchCache","getApiData","redirects","pilimit","pithumbsize","tiny","_createSearchRegEx","_highlightSearchTerm","term","_getPage","pageInfo","displaytext","_processData","search","xhr","isCached","footerAnchor","talkBoard","units","limits","timeAgo","timestampDelta","round","unit","getTimeAgoDelta","isNow","delta","ts","seconds","minutes","hours","days","months","years","getRegistrationMessage","isRecent","storageKey","Toast","requestIdleCallback","_showPending","notification","notify","notif","promises","when","grep","fn","documentElement","isModifiedEvent","altKey","ctrlKey","metaKey","shiftKey","repeatEvent","proxy","WatchstarGateway","Watchstar","funnel","ctaDrawerOptions","campaign","_watched","tooltip","unwatchedClass","watchedClass","onStatusToggleAnon","onStatusToggleUser","checker","postWatched","stopInterval","clearInterval","setInterval","postStatusesByTitle","onStatusToggle","getStatuses","ids","getStatusesByID","getStatusesByTitle","inprop","pageids","rsp","_unmarshalGetResponse","watched","unwatch","wsGateway","_","$item","_appendWatchstar","watchstar","makePanel","panel","AddTopicForm","topicTitlePlaceHolder","topicContentPlaceHolder","input .wikitext-editor, input","change .wikitext-editor, input","disabled","$subject","subject","$body","cols","rows","panels","$messageBody","onTextInput","makeAddTopicForm","TalkSectionAddOverlay","editorApi","click .confirm-save","currentPageTitle","_saveHit","contentHeader","topicForm","$confirm","$ta","confirmMessage","clearTimeout","timer","onSaveClick","isOnTalkPage","status","editMsg","sectiontitle","popup","autosign","TalkSectionOverlay","focus textarea","click .save-button","saveButton","reply","$saveButton","_enableComments","renderFromApi","$commentBox","$textarea","onFocusTextarea","enableSaveButton","response","_ref","board","explanation","global","sandbox","jQuery","dom","mediaWiki","oo","sinon","QUnit","beforeEach","setUp","getSpy","stub","returns","batchcomplete","postSpy","afterEach","tearDown","restore","assert","notStrictEqual","strictEqual","ok","calledWith","spy","postStub","apiReject","apiHappy","apiRvNoSection","apiCaptchaFail","apiAbuseFilterDisallow","apiAbuseFilterWarning","apiAbuseFilterOther","apiTestError","apiReadOnly","apiExpiredToken","apiWithSectionLine","apiHappyTestContent","apiEmptySuccessResponse","apiNoSectionLine","apiRejectHttp","happyResponse","apiReadOnlyResponse","*","0","1","onFirstCall","callCount","notOk","called","rejects","given","propEqual","resolveSpy","rejectSpy","done","async","expectedReturnValue","calledWithMatch","messageStub","getContentStub","previewResolve","withArgs","callback","2","blockedByUser","dBlockedContent","editorOverlay","apiLanguages","zh-min-nan","zh","en","ko","enterText","searcher","trigger","languageSearcher","deepEqual","getCall","apiVariants","structuredLanguages","saveSpy","variantsMap","suggestedLanguage","ImageOverlay","imageGateway","catch","opts","nearby","nearbyGateway","arg","pageimage","primary","globe","msgKm","msgM","toPrecision","pl","watchIconName","notCalled","pageimages","picontinue","warnings","contentmodel","pagelanguage","touched","lastrevid","new","watchlist","firstCall","response1","watchlistraw","mediawiki","tmpDOM","browser4","browser5","browser2","ipad","iphone","android2","animationName","transform","transition","ontouchstart","geolocation","getAttribute","defaultURLs","overrideURLs","pageName","removeChild","outerHTML","callOnPresented","assertHidden","Event","dispatchEvent","bubbles","$viewport","headingNode","TestOverlay","overlays","spies","calledOnce","fakeRouter","routeEvent","createFakeOverlay","fakeOverlay","singleton","showSpy","anotherFakeOverlay","factoryStub","notCalledWith","escapableOverlay","cannotGoBackOverlay","manager","parentFakeOverlay","parentFactoryStub","retryOverlayFn","failedOverlay","successfulOverlay","onCall","stubPage","mobileTocPage","desktopPage","sectionPage","PARSER_OUTPUT","ambox","sectionHeading","sectionSubHeading","sectionBody","expect","testcase","textPage","pLegacyUrls","pNoViewer","pMetadata","pLazyImages","metadataTable","pLazyImagesTypo","pMetadataNested","tc","notMissing","testDesc","json","examples","page2","testData","throws","getPageHeadings","input","output","getPageLanguagesResponse","getPageLanguagesCall","getAPIResponseFromHTML","expected","move","is2","handler","emitSpy","subsection","$section0","mwStorageSetCall","mwStorageSetCall2","mwStorageSetSpy","isEmptyObject","_typeof","localStorageValue","localStorageRemovalValue","expandedSectionsFromToggle","ChildView","EventsView","click p span","click p","onParagraphClick","onClick","view2","textFirstRun","TemplateModeView","ContainerView","click span","memoryCache","foo","expectedError","qux","wbptterms","baz","quux","testCase","headless","gatewayDeferred","actual","attrs","setAttribute","failureImage","successImage","onSecondCall","lazyReferencesLoader","skinPage","$elTwo","$elThree","$elFour","$elFive","TestChild","TestPrototype","testChild","testPrototype","protoMethod","happyView","viewSuccess","viewFailure","sadView","ReferenceDrawer","hideSpy","renderSpy","referencesGateway","referencesPage","ref","referencesGatewayRejector","referencesGatewayEmpty","lazyLoadedReferencesPage","gatewayHitsApi","rlModuleLoader","assertShowHideWorksWhenSuccessful","firstArg","secondArg","thirdArg","60","4","5","talkOverlay","userStub","result2","res","htmlFragment","innerHTML","NaN","testEl","MouseEvent","toastSpy","ctaDrawerSpy","w","postWithTokenDeferred","apiSpy","GET_RESPONSE","pagelanguagehtmlcode","pagelanguagedir","mockAPI","mock","expects","has","An unwatched page","A watched page","verify","never","apiResp","mwApi","formNoInputEvent","form","toastStub","renderFromApiSpy","formNoHandler","references","jsdom","JSDOM","newMockMediaWiki"],"mappings":"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","file":"tests.mobilefrontend.js","sourcesContent":["/*\n *  Copyright 2011 Twitter, Inc.\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\n(function (Hogan) {\n  // Setup regex  assignments\n  // remove whitespace according to Mustache spec\n  var rIsWhitespace = /\\S/,\n      rQuot = /\\\"/g,\n      rNewline =  /\\n/g,\n      rCr = /\\r/g,\n      rSlash = /\\\\/g,\n      tagTypes = {\n        '#': 1, '^': 2, '/': 3,  '!': 4, '>': 5,\n        '<': 6, '=': 7, '_v': 8, '{': 9, '&': 10\n      };\n\n  Hogan.scan = function scan(text, delimiters) {\n    var len = text.length,\n        IN_TEXT = 0,\n        IN_TAG_TYPE = 1,\n        IN_TAG = 2,\n        state = IN_TEXT,\n        tagType = null,\n        tag = null,\n        buf = '',\n        tokens = [],\n        seenTag = false,\n        i = 0,\n        lineStart = 0,\n        otag = '{{',\n        ctag = '}}';\n\n    function addBuf() {\n      if (buf.length > 0) {\n        tokens.push(new String(buf));\n        buf = '';\n      }\n    }\n\n    function lineIsWhitespace() {\n      var isAllWhitespace = true;\n      for (var j = lineStart; j < tokens.length; j++) {\n        isAllWhitespace =\n          (tokens[j].tag && tagTypes[tokens[j].tag] < tagTypes['_v']) ||\n          (!tokens[j].tag && tokens[j].match(rIsWhitespace) === null);\n        if (!isAllWhitespace) {\n          return false;\n        }\n      }\n\n      return isAllWhitespace;\n    }\n\n    function filterLine(haveSeenTag, noNewLine) {\n      addBuf();\n\n      if (haveSeenTag && lineIsWhitespace()) {\n        for (var j = lineStart, next; j < tokens.length; j++) {\n          if (!tokens[j].tag) {\n            if ((next = tokens[j+1]) && next.tag == '>') {\n              // set indent to token value\n              next.indent = tokens[j].toString()\n            }\n            tokens.splice(j, 1);\n          }\n        }\n      } else if (!noNewLine) {\n        tokens.push({tag:'\\n'});\n      }\n\n      seenTag = false;\n      lineStart = tokens.length;\n    }\n\n    function changeDelimiters(text, index) {\n      var close = '=' + ctag,\n          closeIndex = text.indexOf(close, index),\n          delimiters = trim(\n            text.substring(text.indexOf('=', index) + 1, closeIndex)\n          ).split(' ');\n\n      otag = delimiters[0];\n      ctag = delimiters[1];\n\n      return closeIndex + close.length - 1;\n    }\n\n    if (delimiters) {\n      delimiters = delimiters.split(' ');\n      otag = delimiters[0];\n      ctag = delimiters[1];\n    }\n\n    for (i = 0; i < len; i++) {\n      if (state == IN_TEXT) {\n        if (tagChange(otag, text, i)) {\n          --i;\n          addBuf();\n          state = IN_TAG_TYPE;\n        } else {\n          if (text.charAt(i) == '\\n') {\n            filterLine(seenTag);\n          } else {\n            buf += text.charAt(i);\n          }\n        }\n      } else if (state == IN_TAG_TYPE) {\n        i += otag.length - 1;\n        tag = tagTypes[text.charAt(i + 1)];\n        tagType = tag ? text.charAt(i + 1) : '_v';\n        if (tagType == '=') {\n          i = changeDelimiters(text, i);\n          state = IN_TEXT;\n        } else {\n          if (tag) {\n            i++;\n          }\n          state = IN_TAG;\n        }\n        seenTag = i;\n      } else {\n        if (tagChange(ctag, text, i)) {\n          tokens.push({tag: tagType, n: trim(buf), otag: otag, ctag: ctag,\n                       i: (tagType == '/') ? seenTag - ctag.length : i + otag.length});\n          buf = '';\n          i += ctag.length - 1;\n          state = IN_TEXT;\n          if (tagType == '{') {\n            if (ctag == '}}') {\n              i++;\n            } else {\n              cleanTripleStache(tokens[tokens.length - 1]);\n            }\n          }\n        } else {\n          buf += text.charAt(i);\n        }\n      }\n    }\n\n    filterLine(seenTag, true);\n\n    return tokens;\n  }\n\n  function cleanTripleStache(token) {\n    if (token.n.substr(token.n.length - 1) === '}') {\n      token.n = token.n.substring(0, token.n.length - 1);\n    }\n  }\n\n  function trim(s) {\n    if (s.trim) {\n      return s.trim();\n    }\n\n    return s.replace(/^\\s*|\\s*$/g, '');\n  }\n\n  function tagChange(tag, text, index) {\n    if (text.charAt(index) != tag.charAt(0)) {\n      return false;\n    }\n\n    for (var i = 1, l = tag.length; i < l; i++) {\n      if (text.charAt(index + i) != tag.charAt(i)) {\n        return false;\n      }\n    }\n\n    return true;\n  }\n\n  function buildTree(tokens, kind, stack, customTags) {\n    var instructions = [],\n        opener = null,\n        token = null;\n\n    while (tokens.length > 0) {\n      token = tokens.shift();\n      if (token.tag == '#' || token.tag == '^' || isOpener(token, customTags)) {\n        stack.push(token);\n        token.nodes = buildTree(tokens, token.tag, stack, customTags);\n        instructions.push(token);\n      } else if (token.tag == '/') {\n        if (stack.length === 0) {\n          throw new Error('Closing tag without opener: /' + token.n);\n        }\n        opener = stack.pop();\n        if (token.n != opener.n && !isCloser(token.n, opener.n, customTags)) {\n          throw new Error('Nesting error: ' + opener.n + ' vs. ' + token.n);\n        }\n        opener.end = token.i;\n        return instructions;\n      } else {\n        instructions.push(token);\n      }\n    }\n\n    if (stack.length > 0) {\n      throw new Error('missing closing tag: ' + stack.pop().n);\n    }\n\n    return instructions;\n  }\n\n  function isOpener(token, tags) {\n    for (var i = 0, l = tags.length; i < l; i++) {\n      if (tags[i].o == token.n) {\n        token.tag = '#';\n        return true;\n      }\n    }\n  }\n\n  function isCloser(close, open, tags) {\n    for (var i = 0, l = tags.length; i < l; i++) {\n      if (tags[i].c == close && tags[i].o == open) {\n        return true;\n      }\n    }\n  }\n\n  Hogan.generate = function (tree, text, options) {\n    var code = 'var _=this;_.b(i=i||\"\");' + walk(tree) + 'return _.fl();';\n    if (options.asString) {\n      return 'function(c,p,i){' + code + ';}';\n    }\n\n    return new Hogan.Template(new Function('c', 'p', 'i', code), text, Hogan, options);\n  }\n\n  function esc(s) {\n    return s.replace(rSlash, '\\\\\\\\')\n            .replace(rQuot, '\\\\\\\"')\n            .replace(rNewline, '\\\\n')\n            .replace(rCr, '\\\\r');\n  }\n\n  function chooseMethod(s) {\n    return (~s.indexOf('.')) ? 'd' : 'f';\n  }\n\n  function walk(tree) {\n    var code = '';\n    for (var i = 0, l = tree.length; i < l; i++) {\n      var tag = tree[i].tag;\n      if (tag == '#') {\n        code += section(tree[i].nodes, tree[i].n, chooseMethod(tree[i].n),\n                        tree[i].i, tree[i].end, tree[i].otag + \" \" + tree[i].ctag);\n      } else if (tag == '^') {\n        code += invertedSection(tree[i].nodes, tree[i].n,\n                                chooseMethod(tree[i].n));\n      } else if (tag == '<' || tag == '>') {\n        code += partial(tree[i]);\n      } else if (tag == '{' || tag == '&') {\n        code += tripleStache(tree[i].n, chooseMethod(tree[i].n));\n      } else if (tag == '\\n') {\n        code += text('\"\\\\n\"' + (tree.length-1 == i ? '' : ' + i'));\n      } else if (tag == '_v') {\n        code += variable(tree[i].n, chooseMethod(tree[i].n));\n      } else if (tag === undefined) {\n        code += text('\"' + esc(tree[i]) + '\"');\n      }\n    }\n    return code;\n  }\n\n  function section(nodes, id, method, start, end, tags) {\n    return 'if(_.s(_.' + method + '(\"' + esc(id) + '\",c,p,1),' +\n           'c,p,0,' + start + ',' + end + ',\"' + tags + '\")){' +\n           '_.rs(c,p,' +\n           'function(c,p,_){' +\n           walk(nodes) +\n           '});c.pop();}';\n  }\n\n  function invertedSection(nodes, id, method) {\n    return 'if(!_.s(_.' + method + '(\"' + esc(id) + '\",c,p,1),c,p,1,0,0,\"\")){' +\n           walk(nodes) +\n           '};';\n  }\n\n  function partial(tok) {\n    return '_.b(_.rp(\"' +  esc(tok.n) + '\",c,p,\"' + (tok.indent || '') + '\"));';\n  }\n\n  function tripleStache(id, method) {\n    return '_.b(_.t(_.' + method + '(\"' + esc(id) + '\",c,p,0)));';\n  }\n\n  function variable(id, method) {\n    return '_.b(_.v(_.' + method + '(\"' + esc(id) + '\",c,p,0)));';\n  }\n\n  function text(id) {\n    return '_.b(' + id + ');';\n  }\n\n  Hogan.parse = function(tokens, text, options) {\n    options = options || {};\n    return buildTree(tokens, '', [], options.sectionTags || []);\n  },\n\n  Hogan.cache = {};\n\n  Hogan.compile = function(text, options) {\n    // options\n    //\n    // asString: false (default)\n    //\n    // sectionTags: [{o: '_foo', c: 'foo'}]\n    // An array of object with o and c fields that indicate names for custom\n    // section tags. The example above allows parsing of {{_foo}}{{/foo}}.\n    //\n    // delimiters: A string that overrides the default delimiters.\n    // Example: \"<% %>\"\n    //\n    options = options || {};\n\n    var key = text + '||' + !!options.asString;\n\n    var t = this.cache[key];\n\n    if (t) {\n      return t;\n    }\n\n    t = this.generate(this.parse(this.scan(text, options.delimiters), text, options), text, options);\n    return this.cache[key] = t;\n  };\n})(typeof exports !== 'undefined' ? exports : Hogan);\n","/*\n *  Copyright 2011 Twitter, Inc.\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\n// This file is for use with Node.js. See dist/ for browser files.\n\nvar Hogan = require('./compiler');\nHogan.Template = require('./template').Template;\nmodule.exports = Hogan; ","/*\n *  Copyright 2011 Twitter, Inc.\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\nvar Hogan = {};\n\n(function (Hogan, useArrayBuffer) {\n  Hogan.Template = function (renderFunc, text, compiler, options) {\n    this.r = renderFunc || this.r;\n    this.c = compiler;\n    this.options = options;\n    this.text = text || '';\n    this.buf = (useArrayBuffer) ? [] : '';\n  }\n\n  Hogan.Template.prototype = {\n    // render: replaced by generated code.\n    r: function (context, partials, indent) { return ''; },\n\n    // variable escaping\n    v: hoganEscape,\n\n    // triple stache\n    t: coerceToString,\n\n    render: function render(context, partials, indent) {\n      return this.ri([context], partials || {}, indent);\n    },\n\n    // render internal -- a hook for overrides that catches partials too\n    ri: function (context, partials, indent) {\n      return this.r(context, partials, indent);\n    },\n\n    // tries to find a partial in the curent scope and render it\n    rp: function(name, context, partials, indent) {\n      var partial = partials[name];\n\n      if (!partial) {\n        return '';\n      }\n\n      if (this.c && typeof partial == 'string') {\n        partial = this.c.compile(partial, this.options);\n      }\n\n      return partial.ri(context, partials, indent);\n    },\n\n    // render a section\n    rs: function(context, partials, section) {\n      var tail = context[context.length - 1];\n\n      if (!isArray(tail)) {\n        section(context, partials, this);\n        return;\n      }\n\n      for (var i = 0; i < tail.length; i++) {\n        context.push(tail[i]);\n        section(context, partials, this);\n        context.pop();\n      }\n    },\n\n    // maybe start a section\n    s: function(val, ctx, partials, inverted, start, end, tags) {\n      var pass;\n\n      if (isArray(val) && val.length === 0) {\n        return false;\n      }\n\n      if (typeof val == 'function') {\n        val = this.ls(val, ctx, partials, inverted, start, end, tags);\n      }\n\n      pass = (val === '') || !!val;\n\n      if (!inverted && pass && ctx) {\n        ctx.push((typeof val == 'object') ? val : ctx[ctx.length - 1]);\n      }\n\n      return pass;\n    },\n\n    // find values with dotted names\n    d: function(key, ctx, partials, returnFound) {\n      var names = key.split('.'),\n          val = this.f(names[0], ctx, partials, returnFound),\n          cx = null;\n\n      if (key === '.' && isArray(ctx[ctx.length - 2])) {\n        return ctx[ctx.length - 1];\n      }\n\n      for (var i = 1; i < names.length; i++) {\n        if (val && typeof val == 'object' && names[i] in val) {\n          cx = val;\n          val = val[names[i]];\n        } else {\n          val = '';\n        }\n      }\n\n      if (returnFound && !val) {\n        return false;\n      }\n\n      if (!returnFound && typeof val == 'function') {\n        ctx.push(cx);\n        val = this.lv(val, ctx, partials);\n        ctx.pop();\n      }\n\n      return val;\n    },\n\n    // find values with normal names\n    f: function(key, ctx, partials, returnFound) {\n      var val = false,\n          v = null,\n          found = false;\n\n      for (var i = ctx.length - 1; i >= 0; i--) {\n        v = ctx[i];\n        if (v && typeof v == 'object' && key in v) {\n          val = v[key];\n          found = true;\n          break;\n        }\n      }\n\n      if (!found) {\n        return (returnFound) ? false : \"\";\n      }\n\n      if (!returnFound && typeof val == 'function') {\n        val = this.lv(val, ctx, partials);\n      }\n\n      return val;\n    },\n\n    // higher order templates\n    ho: function(val, cx, partials, text, tags) {\n      var compiler = this.c;\n      var options = this.options;\n      options.delimiters = tags;\n      var text = val.call(cx, text);\n      text = (text == null) ? String(text) : text.toString();\n      this.b(compiler.compile(text, options).render(cx, partials));\n      return false;\n    },\n\n    // template result buffering\n    b: (useArrayBuffer) ? function(s) { this.buf.push(s); } :\n                          function(s) { this.buf += s; },\n    fl: (useArrayBuffer) ? function() { var r = this.buf.join(''); this.buf = []; return r; } :\n                           function() { var r = this.buf; this.buf = ''; return r; },\n\n    // lambda replace section\n    ls: function(val, ctx, partials, inverted, start, end, tags) {\n      var cx = ctx[ctx.length - 1],\n          t = null;\n\n      if (!inverted && this.c && val.length > 0) {\n        return this.ho(val, cx, partials, this.text.substring(start, end), tags);\n      }\n\n      t = val.call(cx);\n\n      if (typeof t == 'function') {\n        if (inverted) {\n          return true;\n        } else if (this.c) {\n          return this.ho(t, cx, partials, this.text.substring(start, end), tags);\n        }\n      }\n\n      return t;\n    },\n\n    // lambda replace variable\n    lv: function(val, ctx, partials) {\n      var cx = ctx[ctx.length - 1];\n      var result = val.call(cx);\n\n      if (typeof result == 'function') {\n        result = coerceToString(result.call(cx));\n        if (this.c && ~result.indexOf(\"{\\u007B\")) {\n          return this.c.compile(result, this.options).render(cx, partials);\n        }\n      }\n\n      return coerceToString(result);\n    }\n\n  };\n\n  var rAmp = /&/g,\n      rLt = /</g,\n      rGt = />/g,\n      rApos =/\\'/g,\n      rQuot = /\\\"/g,\n      hChars =/[&<>\\\"\\']/;\n\n\n  function coerceToString(val) {\n    return String((val === null || val === undefined) ? '' : val);\n  }\n\n  function hoganEscape(str) {\n    str = coerceToString(str);\n    return hChars.test(str) ?\n      str\n        .replace(rAmp,'&amp;')\n        .replace(rLt,'&lt;')\n        .replace(rGt,'&gt;')\n        .replace(rApos,'&#39;')\n        .replace(rQuot, '&quot;') :\n      str;\n  }\n\n  var isArray = Array.isArray || function(a) {\n    return Object.prototype.toString.call(a) === '[object Array]';\n  };\n\n})(typeof exports !== 'undefined' ? exports : Hogan);\n\n","var g;\r\n\r\n// This works in non-strict mode\r\ng = (function() {\r\n\treturn this;\r\n})();\r\n\r\ntry {\r\n\t// This works if eval is allowed (see CSP)\r\n\tg = g || Function(\"return this\")() || (1, eval)(\"this\");\r\n} catch (e) {\r\n\t// This works if the window reference is available\r\n\tif (typeof window === \"object\") g = window;\r\n}\r\n\r\n// g can still be undefined, but nothing to do about it...\r\n// We return undefined, instead of nothing here, so it's\r\n// easier to handle this case. if(!global) { ...}\r\n\r\nmodule.exports = g;\r\n","var\n\tprototype,\n\tactionParams = require( '../mobile.startup/actionParams' ),\n\tutil = require( '../mobile.startup/util' ),\n\tSearchGateway = require( '../mobile.startup/search/SearchGateway' );\n\n/**\n * Api for CategoryOverlay\n * @class CategoryGateway\n * @extends SearchGateway\n */\nfunction CategoryGateway() {\n\tCategoryGateway.parent.apply( this, arguments );\n}\nprototype = {\n\t/**\n\t * @memberof CategoryGateway\n\t * @instance\n\t */\n\tcontinueParams: {},\n\t/**\n\t * @memberof CategoryGateway\n\t * @instance\n\t */\n\tcanContinue: true,\n\t/**\n\t * @inheritdoc\n\t * @memberof CategoryGateway\n\t * @instance\n\t */\n\tsearchNamespace: 14,\n\t/**\n\t * Saves the categories passed to this function to the page\n\t * @memberof CategoryGateway\n\t * @instance\n\t * @param {string} title Title of the current page (to add the categories to)\n\t * @param {string} categories List of Categories to add\n\t * @return {jQuery.Deferred}\n\t */\n\tsave: function ( title, categories ) {\n\t\treturn this.api.postWithToken( 'csrf', {\n\t\t\taction: 'edit',\n\t\t\ttitle: title,\n\t\t\tappendtext: categories,\n\t\t\tsummary: mw.msg( 'mobile-frontend-categories-summary' )\n\t\t} );\n\t},\n\t/**\n\t * Returns the categories the title belongs to.\n\t * @memberof CategoryGateway\n\t * @instance\n\t * @param {string} title Title of the current page (to add the categories to)\n\t * @return {jQuery.Deferred|boolean} False, if no further continuation is possible,\n\t *                                   jQuery.Deferred otherwise.\n\t */\n\tgetCategories: function ( title ) {\n\t\tvar self = this, params;\n\n\t\tif ( this.canContinue === false ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tparams = util.extend( {}, {\n\t\t\tprop: 'categories',\n\t\t\ttitles: title,\n\t\t\tclprop: 'hidden',\n\t\t\tcllimit: 50\n\t\t}, this.continueParams );\n\t\treturn this.api.get( actionParams( params ) ).then( function ( data ) {\n\t\t\tif ( data.continue !== undefined ) {\n\t\t\t\tself.continueParams = data.continue;\n\t\t\t} else {\n\t\t\t\tself.canContinue = false;\n\t\t\t}\n\n\t\t\treturn data;\n\t\t} );\n\t}\n};\n\nOO.inheritClass( CategoryGateway, SearchGateway );\nutil.extend( CategoryGateway.prototype, prototype );\n\nmodule.exports = CategoryGateway;\n","var Button = require( '../mobile.startup/Button' ),\n\tutil = require( '../mobile.startup/util' ),\n\tmfExtend = require( '../mobile.startup/mfExtend' ),\n\tOverlay = require( '../mobile.startup/Overlay' );\n\n/**\n * Overlay that shows a message about abuse.\n * This overlay is rendered when the error code from the API\n * is related to the abusefilter extension.\n * @class AbuseFilterOverlay\n * @extends Overlay\n * @param {Object} props\n */\nfunction AbuseFilterOverlay( props ) {\n\tOverlay.call( this,\n\t\tutil.extend( {\n\t\t\tclassName: 'overlay abusefilter-overlay'\n\t\t}, props )\n\t);\n}\n\nmfExtend( AbuseFilterOverlay, Overlay, {\n\t/**\n\t * @memberof AbuseFilterOverlay\n\t * @instance\n\t * @mixes Overlay#defaults\n\t * @property {Object} defaults Default options hash.\n\t * @property {Object} defaults.confirmButton options for a confirm Button\n\t */\n\tdefaults: util.extend( {}, Overlay.prototype.defaults, {\n\t\tconfirmButton: new Button( {\n\t\t\tadditionalClassNames: 'cancel',\n\t\t\tprogressive: true\n\t\t} ).options\n\t} ),\n\t/**\n\t * @memberof AbuseFilterOverlay\n\t * @instance\n\t */\n\ttemplatePartials: util.extend( {}, Overlay.prototype.templatePartials, {\n\t\tbutton: Button.prototype.template,\n\t\tcontent: mw.template.get( 'mobile.editor.overlay', 'AbuseFilterOverlay.hogan' )\n\t} ),\n\t/**\n\t * @inheritdoc\n\t * @memberof AbuseFilterOverlay\n\t * @instance\n\t */\n\tpostRender: function () {\n\t\tOverlay.prototype.postRender.apply( this );\n\t\t// make links open in separate tabs\n\t\tthis.$el.find( 'a' ).attr( 'target', '_blank' );\n\t}\n} );\n\nmodule.exports = AbuseFilterOverlay;\n","var util = require( '../mobile.startup/util' ),\n\tView = require( '../mobile.startup/View' ),\n\tmfExtend = require( '../mobile.startup/mfExtend' ),\n\tAbuseFilterOverlay = require( './AbuseFilterOverlay' );\n\n/**\n * Panel that shows an error message related to the abusefilter extension.\n * @class AbuseFilterPanel\n * @extends View\n * @uses AbuseFilterOverlay\n *\n * @param {Object} options Configuration options\n * FIXME: should extend Panel not View. Or the name should be changed to something meaningful.\n */\nfunction AbuseFilterPanel( options ) {\n\tthis.isDisallowed = false;\n\tthis.overlayManager = options.overlayManager;\n\tView.call( this,\n\t\tutil.extend( {\n\t\t\tclassName: 'panel hidden'\n\t\t}, options )\n\t);\n}\n\nmfExtend( AbuseFilterPanel, View, {\n\t/**\n\t * @memberof AbuseFilterPanel\n\t * @instance\n\t * @mixes View#defaults\n\t * @property {Object} defaults Default options hash.\n\t * @property {string} defaults.readMoreMsg A caption for the button\n\t * allowing the user to read more about the problems with their edit.\n\t * @property {OverlayManager} defaults.overlayManager instance\n\t */\n\tdefaults: {\n\t\treadMoreMsg: mw.msg( 'mobile-frontend-editor-abusefilter-read-more' )\n\t},\n\t/**\n\t * @memberof AbuseFilterPanel\n\t * @instance\n\t */\n\ttemplate: mw.template.get( 'mobile.editor.overlay', 'AbuseFilterPanel.hogan' ),\n\t/**\n\t * Show the panel. Create a route to show AbuseFilterOverlay with message.\n\t * @memberof AbuseFilterPanel\n\t * @instance\n\t * @param {string} type The type of alert, e.g. 'warning' or 'disallow'\n\t * @param {string} message Message to show in the AbuseFilter overlay\n\t */\n\tshow: function ( type, message ) {\n\t\tvar msg;\n\n\t\t// OverlayManager will replace previous instance of the route if present\n\t\tthis.overlayManager.add( /^\\/abusefilter$/, function () {\n\t\t\treturn new AbuseFilterOverlay( {\n\t\t\t\tmessage: message\n\t\t\t} );\n\t\t} );\n\n\t\tif ( type === 'warning' ) {\n\t\t\tmsg = mw.msg( 'mobile-frontend-editor-abusefilter-warning' );\n\t\t} else if ( type === 'disallow' ) {\n\t\t\tmsg = mw.msg( 'mobile-frontend-editor-abusefilter-disallow' );\n\t\t\tthis.isDisallowed = true;\n\t\t}\n\n\t\tthis.$el.find( '.message p' ).text( msg );\n\t\tthis.$el.removeClass( 'hidden' );\n\t},\n\n\t/**\n\t * Hide the panel.\n\t * @memberof AbuseFilterPanel\n\t * @instance\n\t */\n\thide: function () {\n\t\tthis.$el.addClass( 'hidden' );\n\t}\n} );\n\nmodule.exports = AbuseFilterPanel;\n","'use strict';\nvar Drawer = require( '../mobile.startup/Drawer' ),\n\tButton = require( '../mobile.startup/Button' ),\n\tmfExtend = require( '../mobile.startup/mfExtend' ),\n\tIcon = require( '../mobile.startup/Icon' ),\n\tutil = require( '../mobile.startup/util' );\n\n/**\n * This creates the drawer at the bottom of the screen that appears when a\n * blocked user tries to edit.\n * @class BlockReason\n * @extends Drawer\n */\nfunction BlockMessage() {\n\tDrawer.apply( this, arguments );\n}\n\nmfExtend( BlockMessage, Drawer, {\n\t/**\n\t * @memberof BlockMessage\n\t * @instance\n\t */\n\tdefaults: util.extend( {}, Drawer.prototype.defaults, {\n\t\tstopHandIcon: new Icon( {\n\t\t\tname: 'stop-hand'\n\t\t} ).options,\n\t\tuserIcon: new Icon( {\n\t\t\ttagName: 'span',\n\t\t\tname: 'profile'\n\t\t} ).options,\n\t\tokButton: new Button( {\n\t\t\tlabel: mw.msg( 'ok' ),\n\t\t\ttagName: 'button',\n\t\t\tprogressive: true,\n\t\t\tadditionalClassNames: 'cancel'\n\t\t} ).options,\n\t\tcreateDetailsAnchorHref: function () {\n\t\t\treturn mw.util.getUrl( 'Special:BlockList', { wpTarget: '#' + this.blockId } );\n\t\t},\n\t\tcreateDetailsAnchorLabel: function () {\n\t\t\treturn mw.msg( 'mobile-frontend-editor-blocked-drawer-help' );\n\t\t},\n\t\tcreateTitle: function () {\n\t\t\treturn this.partial ? mw.msg( 'mobile-frontend-editor-blocked-drawer-title-partial' ) : mw.msg( 'mobile-frontend-editor-blocked-drawer-title' );\n\t\t},\n\t\treasonHeader: mw.msg( 'mobile-frontend-editor-blocked-drawer-reason-header' ),\n\t\tcreatorHeader: function () {\n\t\t\t// The gender is the subject (the blockee) not the object (the blocker).\n\t\t\treturn mw.msg( 'mobile-frontend-editor-blocked-drawer-creator-header',\n\t\t\t\tthis.user.options.gender || 'unknown' );\n\t\t},\n\t\texpiryHeader: mw.msg( 'mobile-frontend-editor-blocked-drawer-expiry-header' )\n\t} ),\n\t/**\n\t * @memberof BlockMessage\n\t * @instance\n\t */\n\ttemplatePartials: util.extend( {}, Drawer.prototype.templatePartials, {\n\t\tbutton: Button.prototype.template,\n\t\ticon: Icon.prototype.template\n\t} ),\n\t/**\n\t * @memberof BlockMessage\n\t * @instance\n\t */\n\ttemplate: mw.template.get( 'mobile.editor.overlay', 'BlockMessage.hogan' )\n} );\n\nmodule.exports = BlockMessage;\n","var util = require( '../mobile.startup/util' ),\n\tparseSaveError = require( './parseSaveError' ),\n\tactionParams = require( '../mobile.startup/actionParams' );\n\n/**\n * API that helps save and retrieve page content\n * @class EditorGateway\n *\n * @param {Object} options Configuration options\n * @param {mw.Api} options.api an Api to use.\n * @param {string} options.title the title to edit\n * @param {number} options.sectionId the id of the section to operate edits on.\n * @param {number} [options.oldId] revision to operate on. If absent defaults to latest.\n * @param {boolean} [options.isNewPage] whether the page being created is new\n */\nfunction EditorGateway( options ) {\n\tthis.api = options.api;\n\tthis.title = options.title;\n\tthis.sectionId = options.sectionId;\n\tthis.oldId = options.oldId;\n\t// return an empty section for new pages\n\tthis.content = options.isNewPage ? '' : undefined;\n\tthis.hasChanged = false;\n}\n\nEditorGateway.prototype = {\n\t/**\n\t * Get the block (if there is one) from the result.\n\t * @memberof EditorGateway\n\t * @param {Object} pageObj\n\t * @return {Object|null}\n\t */\n\tgetBlockInfo: function ( pageObj ) {\n\t\tvar blockedError;\n\n\t\tif ( pageObj.actions &&\n\t\t\tpageObj.actions.edit &&\n\t\t\tArray.isArray( pageObj.actions.edit )\n\t\t) {\n\t\t\tpageObj.actions.edit.some( function ( error ) {\n\t\t\t\tif ( [ 'blocked', 'autoblocked' ].indexOf( error.code ) !== -1 ) {\n\t\t\t\t\tblockedError = error;\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t} );\n\n\t\t\tif ( blockedError && blockedError.data && blockedError.data.blockinfo ) {\n\t\t\t\t// Preload library used by EditorOverlay\n\t\t\t\t// to format block expiry datetime and duration\n\t\t\t\tmw.loader.load( 'moment' );\n\n\t\t\t\treturn blockedError.data.blockinfo;\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t},\n\t/**\n\t * Get the content of a page.\n\t * @memberof EditorGateway\n\t * @instance\n\t * @return {jQuery.Promise}\n\t */\n\tgetContent: function () {\n\t\tvar options,\n\t\t\tself = this;\n\n\t\tfunction resolve() {\n\t\t\treturn util.Deferred().resolve( {\n\t\t\t\ttext: self.content || '',\n\t\t\t\tblockinfo: self.blockinfo,\n\t\t\t\tuserinfo: self.userinfo\n\t\t\t} );\n\t\t}\n\n\t\tif ( this.content !== undefined ) {\n\t\t\treturn resolve();\n\t\t} else {\n\t\t\toptions = actionParams( {\n\t\t\t\tprop: [ 'revisions', 'info' ],\n\t\t\t\tmeta: 'userinfo',\n\t\t\t\trvprop: [ 'content', 'timestamp' ],\n\t\t\t\ttitles: self.title,\n\t\t\t\t// get block information for this user\n\t\t\t\tintestactions: 'edit',\n\t\t\t\tintestactionsdetail: 'full',\n\t\t\t\tuiprop: 'options'\n\t\t\t} );\n\t\t\t// Load text of old revision if desired\n\t\t\tif ( this.oldId ) {\n\t\t\t\toptions.rvstartid = this.oldId;\n\t\t\t}\n\t\t\t// See Bug 50136 - passing rvsection will fail with non wikitext\n\t\t\tif ( util.isNumeric( this.sectionId ) ) {\n\t\t\t\toptions.rvsection = this.sectionId;\n\t\t\t}\n\t\t\treturn this.api.get( options ).then( function ( resp ) {\n\t\t\t\tvar revision, pageObj;\n\n\t\t\t\tif ( resp.error ) {\n\t\t\t\t\treturn util.Deferred().reject( resp.error.code );\n\t\t\t\t}\n\n\t\t\t\tpageObj = resp.query.pages[0];\n\t\t\t\t// page might not exist and caller might not have known.\n\t\t\t\tif ( pageObj.missing !== undefined ) {\n\t\t\t\t\tself.content = '';\n\t\t\t\t} else {\n\t\t\t\t\trevision = pageObj.revisions[0];\n\t\t\t\t\tself.content = revision.content;\n\t\t\t\t\tself.timestamp = revision.timestamp;\n\t\t\t\t}\n\n\t\t\t\tself.userinfo = resp.query.userinfo;\n\n\t\t\t\t// save content a second time to be able to check for changes\n\t\t\t\tself.originalContent = self.content;\n\t\t\t\tself.blockinfo = self.getBlockInfo( pageObj );\n\n\t\t\t\treturn resolve();\n\t\t\t} );\n\t\t}\n\t},\n\n\t/**\n\t * Mark content as modified and set changes to be submitted when #save\n\t * is invoked.\n\t * @memberof EditorGateway\n\t * @instance\n\t * @param {string} content New section content.\n\t */\n\tsetContent: function ( content ) {\n\t\tif ( this.originalContent !== content ) {\n\t\t\tthis.hasChanged = true;\n\t\t} else {\n\t\t\tthis.hasChanged = false;\n\t\t}\n\t\tthis.content = content;\n\t},\n\n\t/**\n\t * Mark content as modified and set text that should be prepended to given\n\t * section when #save is invoked.\n\t * @memberof EditorGateway\n\t * @instance\n\t * @param {string} text Text to be prepended.\n\t */\n\tsetPrependText: function ( text ) {\n\t\tthis.prependtext = text;\n\t\tthis.hasChanged = true;\n\t},\n\n\t/**\n\t * Save the new content of the section, previously set using #setContent.\n\t * @memberof EditorGateway\n\t * @instance\n\t * @param {Object} options Configuration options\n\t * @param {string} [options.summary] Optional summary for the edit.\n\t * @param {string} [options.captchaId] If CAPTCHA was requested, ID of the\n\t * captcha.\n\t * @param {string} [options.captchaWord] If CAPTCHA was requested, term\n\t * displayed in the CAPTCHA.\n\t * @return {jQuery.Deferred} On failure callback is passed an object with\n\t * `type` and `details` properties. `type` is a string describing the type\n\t * of error, `details` can be any object (usually error message).\n\t */\n\tsave: function ( options ) {\n\t\tvar self = this,\n\t\t\tresult = util.Deferred();\n\n\t\toptions = options || {};\n\n\t\t/**\n\t\t * Save content. Make an API request.\n\t\t * @return {jQuery.Deferred}\n\t\t */\n\t\tfunction saveContent() {\n\t\t\tvar apiOptions = {\n\t\t\t\taction: 'edit',\n\t\t\t\ttitle: self.title,\n\t\t\t\tsummary: options.summary,\n\t\t\t\tcaptchaid: options.captchaId,\n\t\t\t\tcaptchaword: options.captchaWord,\n\t\t\t\tbasetimestamp: self.timestamp,\n\t\t\t\tstarttimestamp: self.timestamp\n\t\t\t};\n\n\t\t\tif ( self.content !== undefined ) {\n\t\t\t\tapiOptions.text = self.content;\n\t\t\t} else if ( self.prependtext ) {\n\t\t\t\tapiOptions.prependtext = self.prependtext;\n\t\t\t}\n\n\t\t\tif ( util.isNumeric( self.sectionId ) ) {\n\t\t\t\tapiOptions.section = self.sectionId;\n\t\t\t}\n\n\t\t\tself.api.postWithToken( 'csrf', apiOptions ).then( function ( data ) {\n\t\t\t\tif ( data && data.edit && data.edit.result === 'Success' ) {\n\t\t\t\t\tself.hasChanged = false;\n\t\t\t\t\tresult.resolve();\n\t\t\t\t} else {\n\t\t\t\t\tresult.reject( parseSaveError( data ) );\n\t\t\t\t}\n\t\t\t}, function ( code, data ) {\n\t\t\t\tresult.reject( parseSaveError( data, code || 'unknown' ) );\n\t\t\t} );\n\t\t\treturn result;\n\t\t}\n\n\t\treturn saveContent();\n\t},\n\n\t/**\n\t * Abort any pending previews.\n\t * @memberof EditorGateway\n\t * @instance\n\t */\n\tabortPreview: function () {\n\t\tif ( this._pending ) {\n\t\t\tthis._pending.abort();\n\t\t}\n\t},\n\n\t/**\n\t * Get page preview from the API and abort any existing previews.\n\t * @memberof EditorGateway\n\t * @instance\n\t * @param {Object} options API query parameters\n\t * @return {jQuery.Deferred}\n\t */\n\tgetPreview: function ( options ) {\n\t\tvar result = util.Deferred(),\n\t\t\tsectionLine = '',\n\t\t\tsectionId = '',\n\t\t\trequest,\n\t\t\tself = this;\n\n\t\tutil.extend( options, {\n\t\t\taction: 'parse',\n\t\t\t// Enable section preview mode to avoid errors (bug 49218)\n\t\t\tsectionpreview: true,\n\t\t\t// needed for pre-save transform to work (bug 53692)\n\t\t\tpst: true,\n\t\t\t// Output mobile HTML (bug 54243)\n\t\t\tmobileformat: true,\n\t\t\ttitle: this.title,\n\t\t\tprop: [ 'text', 'sections' ]\n\t\t} );\n\n\t\tthis.abortPreview();\n\n\t\trequest = this.api.post( options );\n\t\tthis._pending = request.then( function ( resp ) {\n\t\t\tif ( resp && resp.parse && resp.parse.text ) {\n\t\t\t\t// section 0 haven't a section name so skip\n\t\t\t\tif ( self.sectionId !== 0 &&\n\t\t\t\t\tresp.parse.sections !== undefined &&\n\t\t\t\t\tresp.parse.sections[0] !== undefined\n\t\t\t\t) {\n\t\t\t\t\tif ( resp.parse.sections[0].anchor !== undefined ) {\n\t\t\t\t\t\tsectionId = resp.parse.sections[0].anchor;\n\t\t\t\t\t}\n\t\t\t\t\tif ( resp.parse.sections[0].line !== undefined ) {\n\t\t\t\t\t\tsectionLine = resp.parse.sections[0].line;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tresult.resolve( {\n\t\t\t\t\ttext: resp.parse.text['*'],\n\t\t\t\t\tid: sectionId,\n\t\t\t\t\tline: sectionLine\n\t\t\t\t} );\n\t\t\t} else {\n\t\t\t\tresult.reject();\n\t\t\t}\n\t\t}, function () {\n\t\t\tresult.reject();\n\t\t} ).promise( {\n\t\t\tabort: function () { request.abort(); }\n\t\t} );\n\n\t\treturn result;\n\t}\n};\n\nmodule.exports = EditorGateway;\n","var EditorOverlayBase = require( './EditorOverlayBase' ),\n\tutil = require( '../mobile.startup/util' ),\n\tSection = require( '../mobile.startup/Section' ),\n\tsaveFailureMessage = require( './saveFailureMessage' ),\n\tEditorGateway = require( './EditorGateway' ),\n\tAbuseFilterPanel = require( './AbuseFilterPanel' ),\n\tButton = require( '../mobile.startup/Button' ),\n\tmfExtend = require( '../mobile.startup/mfExtend' ),\n\tBlockMessage = require( './BlockMessage' ),\n\tVisualEditorOverlay = require( './VisualEditorOverlay' ),\n\tMessageBox = require( '../mobile.startup/MessageBox' );\n\n/**\n * Overlay that shows an editor\n * @class EditorOverlay\n * @uses Section\n * @uses AbuseFilterPanel\n * @uses EditorGateway\n * @uses VisualEditorOverlay\n * @extends EditorOverlayBase\n *\n * @param {Object} options Configuration options\n */\nfunction EditorOverlay( options ) {\n\tthis.isFirefox = /firefox/i.test( window.navigator.userAgent );\n\tthis.gateway = new EditorGateway( {\n\t\tapi: options.api,\n\t\ttitle: options.title,\n\t\tsectionId: options.sectionId,\n\t\toldId: options.oldId,\n\t\tisNewPage: options.isNewPage\n\t} );\n\tthis.readOnly = !!options.oldId; // If old revision, readOnly mode\n\tif ( this.isVisualEditorEnabled() ) {\n\t\toptions.editSwitcher = true;\n\t}\n\tif ( this.readOnly ) {\n\t\toptions.readOnly = true;\n\t\toptions.editingMsg = mw.msg( 'mobile-frontend-editor-viewing-source-page', options.title );\n\t} else {\n\t\toptions.editingMsg = mw.msg( 'mobile-frontend-editor-editing-page', options.title );\n\t}\n\t// be explicit here. This may have been initialized from VE.\n\toptions.isVisualEditor = false;\n\toptions.previewingMsg = mw.msg( 'mobile-frontend-editor-previewing-page', options.title );\n\tEditorOverlayBase.call(\n\t\tthis,\n\t\tutil.extend( true,\n\t\t\t{ events: { 'input .wikitext-editor': 'onInputWikitextEditor' } },\n\t\t\toptions\n\t\t)\n\t);\n}\n\nmfExtend( EditorOverlay, EditorOverlayBase, {\n\t/**\n\t * @inheritdoc\n\t * @memberof EditorOverlay\n\t * @instance\n\t */\n\ttemplatePartials: util.extend( {}, EditorOverlayBase.prototype.templatePartials, {\n\t\tcontent: mw.template.get( 'mobile.editor.overlay', 'content.hogan' )\n\t} ),\n\t/**\n\t * @memberof EditorOverlay\n\t * @instance\n\t */\n\teditor: 'wikitext',\n\t/**\n\t * @memberof EditorOverlay\n\t * @instance\n\t */\n\tsectionLine: '',\n\n\t/**\n\t * Check whether VisualEditor is enabled or not.\n\t * @memberof EditorOverlay\n\t * @instance\n\t * @return {boolean}\n\t */\n\tisVisualEditorEnabled: function () {\n\t\tvar ns = mw.config.get( 'wgVisualEditorConfig' ) &&\n\t\t\tmw.config.get( 'wgVisualEditorConfig' ).namespaces;\n\n\t\treturn ns &&\n\t\t\tns.indexOf(\n\t\t\t\tmw.config.get( 'wgNamespaceNumber' )\n\t\t\t) > -1 &&\n\t\t\tmw.config.get( 'wgTranslatePageTranslation' ) !== 'translation' &&\n\t\t\tmw.config.get( 'wgPageContentModel' ) === 'wikitext';\n\t},\n\t/**\n\t * Wikitext Editor input handler\n\t * @memberof EditorOverlay\n\t * @instance\n\t */\n\tonInputWikitextEditor: function () {\n\t\tthis.gateway.setContent( this.$el.find( '.wikitext-editor' ).val() );\n\t\tthis.$el.find( '.continue, .submit' ).prop( 'disabled', false );\n\t},\n\t/**\n\t * @inheritdoc\n\t * @memberof EditorOverlay\n\t * @instance\n\t */\n\tonClickContinue: function ( ev ) {\n\t\t// handle the click on \"Edit without logging in\"\n\t\tif ( this.options.isAnon && this.$el.find( ev.target ).hasClass( 'anonymous' ) ) {\n\t\t\tthis._showEditorAfterWarning();\n\t\t\treturn false;\n\t\t}\n\t\tEditorOverlayBase.prototype.onClickContinue.apply( this, arguments );\n\t},\n\t/**\n\t * @inheritdoc\n\t * @memberof EditorOverlay\n\t * @instance\n\t */\n\tonClickBack: function () {\n\t\tEditorOverlayBase.prototype.onClickBack.apply( this, arguments );\n\t\tthis._hidePreview();\n\t},\n\t/**\n\t * @inheritdoc\n\t * @memberof EditorOverlay\n\t * @instance\n\t */\n\tpostRender: function () {\n\t\tvar self = this,\n\t\t\toptions = this.options,\n\t\t\t$anonWarning = this.$el.find( '.anonwarning' );\n\n\t\tif ( this.isVisualEditorEnabled() ) {\n\t\t\tmw.loader.using( 'ext.visualEditor.switching' ).then( function () {\n\t\t\t\tvar switchToolbar,\n\t\t\t\t\ttoolFactory = new OO.ui.ToolFactory(),\n\t\t\t\t\ttoolGroupFactory = new OO.ui.ToolGroupFactory();\n\n\t\t\t\ttoolFactory.register( mw.libs.ve.MWEditModeVisualTool );\n\t\t\t\ttoolFactory.register( mw.libs.ve.MWEditModeSourceTool );\n\t\t\t\tswitchToolbar = new OO.ui.Toolbar( toolFactory, toolGroupFactory, {\n\t\t\t\t\tclasses: [ 'editor-switcher' ]\n\t\t\t\t} );\n\n\t\t\t\tswitchToolbar.on( 'switchEditor', function ( mode ) {\n\t\t\t\t\tif ( mode === 'visual' ) {\n\t\t\t\t\t\t// If the user tries to switch to the VisualEditor,\n\t\t\t\t\t\t// check if any changes have been made,\n\t\t\t\t\t\t// and if so, tell the user they have to save first.\n\t\t\t\t\t\tif ( !self.gateway.hasChanged ) {\n\t\t\t\t\t\t\t// TODO: Be more selective in which options we pass between editors\n\t\t\t\t\t\t\tself._switchToVisualEditor( self.options );\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// TODO: Replace with an OOUI dialog\n\t\t\t\t\t\t\tif ( window.confirm( mw.msg( 'mobile-frontend-editor-switch-confirm' ) ) ) {\n\t\t\t\t\t\t\t\tself.onStageChanges();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} );\n\n\t\t\t\tswitchToolbar.setup( [\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'editMode',\n\t\t\t\t\t\ttype: 'list',\n\t\t\t\t\t\ticon: 'edit',\n\t\t\t\t\t\ttitle: mw.msg( 'visualeditor-mweditmode-tooltip' ),\n\t\t\t\t\t\tinclude: [ 'editModeVisual', 'editModeSource' ]\n\t\t\t\t\t}\n\t\t\t\t] );\n\n\t\t\t\tself.$el.find( '.switcher-container' ).html( switchToolbar.$element );\n\t\t\t\tswitchToolbar.emit( 'updateState' );\n\t\t\t} );\n\t\t}\n\n\t\tEditorOverlayBase.prototype.postRender.apply( this );\n\n\t\tthis.$preview = this.$el.find( '.preview' );\n\t\tthis.$content = this.$el.find( '.wikitext-editor' );\n\t\tthis.$content.addClass( 'mw-editfont-' + mw.user.options.get( 'editfont' ) );\n\t\tif ( options.isAnon ) {\n\t\t\t// add anonymous warning actions if present\n\t\t\tif ( $anonWarning.length ) {\n\t\t\t\t$anonWarning.find( ' > div' ).prepend(\n\t\t\t\t\tnew MessageBox( {\n\t\t\t\t\t\tclassName: 'warningbox anon-msg',\n\t\t\t\t\t\tmsg: mw.msg( 'mobile-frontend-editor-anonwarning' )\n\t\t\t\t\t} ).$el\n\t\t\t\t);\n\t\t\t\tif ( options.isAnon ) {\n\t\t\t\t\tthis._renderAnonWarning( $anonWarning, options );\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.$anonWarning = $anonWarning;\n\t\t\tthis.$content.hide();\n\t\t\t// the user has to click login, signup or edit without login,\n\t\t\t// disable \"Next\" button on top right\n\t\t\tthis.$anonHiddenButtons = this.$el.find( '.overlay-header .continue, .editor-switcher' ).hide();\n\t\t\tthis.hideSpinner();\n\t\t}\n\t\t// make license links open in separate tabs\n\t\tthis.$el.find( '.license a' ).attr( 'target', '_blank' );\n\n\t\tthis.abuseFilterPanel = new AbuseFilterPanel( {\n\t\t\toverlayManager: this.overlayManager\n\t\t} ).appendTo( this.$el.find( '.panels' ) );\n\n\t\t// If in readOnly mode, make textarea readonly\n\t\tif ( this.readOnly ) {\n\t\t\tthis.$content.prop( 'readonly', true );\n\t\t}\n\n\t\tthis.$content.on( 'input', this._resizeEditor.bind( this ) );\n\n\t\tif ( !self.options.isAnon ) {\n\t\t\tthis._loadContent();\n\t\t}\n\t},\n\n\t/**\n\t * Sets additional values used for anonymous editing warning.\n\t * @memberof EditorOverlay\n\t * @instance\n\t * @private\n\t * @param {jQuery.Element} $anonWarning\n\t * @param {Object} options\n\t */\n\t_renderAnonWarning: function ( $anonWarning, options ) {\n\t\tvar params = util.extend( {\n\t\t\t// use wgPageName as this includes the namespace if outside Main\n\t\t\t\treturnto: options.returnTo || mw.config.get( 'wgPageName' ),\n\t\t\t\treturntoquery: 'action=edit&section=' + options.sectionId,\n\t\t\t\twarning: 'mobile-frontend-edit-login-action'\n\t\t\t}, options.queryParams ),\n\t\t\tsignupParams = util.extend( {\n\t\t\t\ttype: 'signup',\n\t\t\t\twarning: 'mobile-frontend-edit-signup-action'\n\t\t\t}, options.signupQueryParams ),\n\t\t\tanonymousEditorActions = [\n\t\t\t\tnew Button( {\n\t\t\t\t\tlabel: mw.msg( 'mobile-frontend-editor-anon' ),\n\t\t\t\t\tblock: true,\n\t\t\t\t\tadditionalClassNames: 'continue anonymous',\n\t\t\t\t\tprogressive: true\n\t\t\t\t} ),\n\t\t\t\tnew Button( {\n\t\t\t\t\tblock: true,\n\t\t\t\t\thref: mw.util.getUrl( 'Special:UserLogin', params ),\n\t\t\t\t\tlabel: mw.msg( 'mobile-frontend-watchlist-cta-button-login' )\n\t\t\t\t} ),\n\t\t\t\tnew Button( {\n\t\t\t\t\tblock: true,\n\t\t\t\t\thref: mw.util.getUrl( 'Special:UserLogin', util.extend( params, signupParams ) ),\n\t\t\t\t\tlabel: mw.msg( 'mobile-frontend-watchlist-cta-button-signup' )\n\t\t\t\t} )\n\t\t\t];\n\n\t\t$anonWarning.find( '.actions' ).append(\n\t\t\tanonymousEditorActions.map( function ( action ) {\n\t\t\t\treturn action.$el;\n\t\t\t} )\n\t\t);\n\t},\n\n\t/**\n\t * Handles click on \"Edit without login\" in anonymous editing warning.\n\t * @memberof EditorOverlay\n\t * @instance\n\t * @private\n\t */\n\t_showEditorAfterWarning: function () {\n\t\tthis.showSpinner();\n\t\tthis.$anonWarning.hide();\n\t\t// reenable \"Next\" button\n\t\tthis.$anonHiddenButtons.show();\n\t\tthis._loadContent();\n\t},\n\n\t/**\n\t * Prepares the preview interface and reveals the save screen of the overlay\n\t * @inheritdoc\n\t * @memberof EditorOverlay\n\t * @instance\n\t */\n\tonStageChanges: function () {\n\t\tvar self = this,\n\t\t\tparams = {\n\t\t\t\ttext: this.getContent()\n\t\t\t};\n\n\t\tthis.scrollTop = util.getDocument().find( 'body' ).scrollTop();\n\t\tthis.$content.hide();\n\t\tthis.showSpinner();\n\n\t\tif ( mw.config.get( 'wgIsMainPage' ) ) {\n\t\t\tparams.mainpage = 1; // Setting it to 0 will have the same effect\n\t\t}\n\n\t\tfunction hideSpinnerAndShowPreview() {\n\t\t\tself.hideSpinner();\n\t\t\tself.$preview.show();\n\t\t}\n\n\t\tthis.gateway.getPreview( params ).then( function ( result ) {\n\t\t\tvar parsedText = result.text,\n\t\t\t\tparsedSectionLine = result.line;\n\n\t\t\tself.sectionId = result.id;\n\t\t\t// On desktop edit summaries strip tags. Mimic this behavior on mobile devices\n\t\t\tself.sectionLine = self.parseHTML( '<div>' ).html( parsedSectionLine ).text();\n\t\t\tnew Section( {\n\t\t\t\tel: self.$preview,\n\t\t\t\ttext: parsedText\n\t\t\t} ).$el.find( 'a' ).on( 'click', false );\n\n\t\t\thideSpinnerAndShowPreview();\n\t\t}, function () {\n\t\t\tself.$preview.addClass( 'error' ).text( mw.msg( 'mobile-frontend-editor-error-preview' ) );\n\n\t\t\thideSpinnerAndShowPreview();\n\t\t} );\n\n\t\tEditorOverlayBase.prototype.onStageChanges.apply( this, arguments );\n\t},\n\n\t/**\n\t * Hides the preview and reverts back to initial screen.\n\t * @memberof EditorOverlay\n\t * @instance\n\t * @private\n\t */\n\t_hidePreview: function () {\n\t\tthis.gateway.abortPreview();\n\t\tthis.hideSpinner();\n\t\tthis.$preview.removeClass( 'error' ).hide();\n\t\tthis.$content.show();\n\t\twindow.scrollTo( 0, this.scrollTop );\n\t\tthis.showHidden( '.initial-header' );\n\t\tthis.abuseFilterPanel.hide();\n\t},\n\n\t/**\n\t * Resize the editor textarea, maintaining scroll position in iOS\n\t * @memberof EditorOverlay\n\t * @instance\n\t */\n\t_resizeEditor: function () {\n\t\tvar scrollTop, container, $scrollContainer;\n\n\t\t// exiting early for firefox due to a bug that causes the page to scroll to top\n\t\t// whenever a caret is inserted T214880\n\t\tif ( this.isFirefox ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !this.$scrollContainer ) {\n\t\t\tcontainer = OO.ui.Element.static\n\t\t\t\t.getClosestScrollableContainer( this.$content[ 0 ] );\n\t\t\t// The scroll container will be either within the view\n\t\t\t// or the document element itself.\n\t\t\t$scrollContainer = this.$el.find( container ).length ?\n\t\t\t\tthis.$el.find( container ) : util.getDocument();\n\t\t\tthis.$scrollContainer = $scrollContainer;\n\t\t\tthis.$content.css( 'padding-bottom', this.$scrollContainer.height() * 0.6 );\n\t\t} else {\n\t\t\t$scrollContainer = this.$scrollContainer;\n\t\t}\n\n\t\t// Only do this if scroll container exists\n\t\tif ( this.$content.prop( 'scrollHeight' ) && $scrollContainer.length ) {\n\t\t\tscrollTop = $scrollContainer.scrollTop();\n\t\t\tthis.$content\n\t\t\t\t.css( 'height', 'auto' )\n\t\t\t\t// can't reuse prop( 'scrollHeight' ) because we need the current value\n\t\t\t\t.css( 'height', ( this.$content.prop( 'scrollHeight' ) + 2 ) + 'px' );\n\t\t\t$scrollContainer.scrollTop( scrollTop );\n\t\t}\n\t},\n\n\t/**\n\t * Set content to the user input field.\n\t * @memberof EditorOverlay\n\t * @instance\n\t * @param {string} content The content to set.\n\t */\n\tsetContent: function ( content ) {\n\t\tthis.$content\n\t\t\t.show()\n\t\t\t.val( content );\n\t\tthis._resizeEditor();\n\t},\n\n\t/**\n\t * Returns the content of the user input field.\n\t * @memberof EditorOverlay\n\t * @instance\n\t * @return {string}\n\t */\n\tgetContent: function () {\n\t\treturn this.$content.val();\n\t},\n\n\t/**\n\t * @memberof EditorOverlay\n\t * @instance\n\t * @param {string} data\n\t * @return {string|false}\n\t */\n\t_parseBlockInfo: function ( data ) {\n\t\tvar blockInfo, expiry, reason,\n\t\t\tmoment = window.moment;\n\n\t\t// Workaround to parse a message parameter for mw.message, see T96885\n\t\tfunction jqueryMsgParse( wikitext ) {\n\t\t\tvar parser, ast;\n\t\t\t// eslint-disable-next-line new-cap\n\t\t\tparser = new mw.jqueryMsg.parser();\n\t\t\ttry {\n\t\t\t\tast = parser.wikiTextToAst( wikitext );\n\t\t\t\treturn parser.emitter.emit( ast ).html();\n\t\t\t} catch ( e ) {\n\t\t\t\t// Ignore error as it's probably the parser error. Usually this is because we\n\t\t\t\t// can't parse templates.\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\tblockInfo = {\n\t\t\tpartial: data.blockinfo.blockpartial || false,\n\t\t\tuser: data.userinfo,\n\t\t\tcreator: {\n\t\t\t\tname: data.blockinfo.blockedby,\n\t\t\t\t// NS_USER === 2\n\t\t\t\turl: mw.util.getUrl(\n\t\t\t\t\tmw.config.get( 'wgFormattedNamespaces' )[2] + ':' +\n\t\t\t\t\tdata.blockinfo.blockedby\n\t\t\t\t)\n\t\t\t},\n\t\t\texpiry: null,\n\t\t\tduration: null,\n\t\t\treason: '',\n\t\t\tblockId: data.blockinfo.blockid\n\t\t};\n\n\t\texpiry = data.blockinfo.blockexpiry;\n\t\tif ( [ 'infinite', 'indefinite', 'infinity', 'never' ].indexOf( expiry ) === -1 ) {\n\t\t\tblockInfo.expiry = moment( expiry ).format( 'LLL' );\n\t\t\tblockInfo.duration = moment().to( expiry, true );\n\t\t}\n\n\t\treason = data.blockinfo.blockreason;\n\t\tif ( reason ) {\n\t\t\tblockInfo.reason = jqueryMsgParse( reason ) || mw.html.escape( reason );\n\t\t} else {\n\t\t\tblockInfo.reason = mw.message( 'mobile-frontend-editor-generic-block-reason' ).escaped();\n\t\t}\n\n\t\treturn blockInfo;\n\t},\n\n\t/**\n\t * Requests content from the API and reveals it in UI.\n\t * @memberof EditorOverlay\n\t * @instance\n\t * @private\n\t */\n\t_loadContent: function () {\n\t\tvar self = this,\n\t\t\t$el = this.$el;\n\n\t\tthis.$content.hide();\n\t\tthis.showSpinner();\n\t\t$el.addClass( 'overlay-loading' );\n\n\t\tthis.gateway.getContent()\n\t\t\t.then( function ( result ) {\n\t\t\t\tvar block, message,\n\t\t\t\t\tcontent = result.text;\n\n\t\t\t\tself.setContent( content );\n\t\t\t\t// check if user is blocked\n\t\t\t\tif ( result.blockinfo ) {\n\t\t\t\t\t// Lazy-load moment only if it's needed,\n\t\t\t\t\t// it's somewhat large (it is already used on\n\t\t\t\t\t// mobile by Echo's notifications panel, where it's also lazy-loaded)\n\t\t\t\t\tmw.loader.using( 'moment' ).then( function () {\n\t\t\t\t\t\tblock = self._parseBlockInfo( result );\n\t\t\t\t\t\tmessage = new BlockMessage( block );\n\t\t\t\t\t\tmessage.toggle();\n\t\t\t\t\t\tself.hide();\n\t\t\t\t\t\tself.hideSpinner();\n\t\t\t\t\t\t$el.removeClass( 'overlay-loading' );\n\t\t\t\t\t} );\n\t\t\t\t} else {\n\t\t\t\t\tself.hideSpinner();\n\t\t\t\t\t$el.removeClass( 'overlay-loading' );\n\t\t\t\t}\n\t\t\t}, function () {\n\t\t\t\tself.reportError( mw.msg( 'mobile-frontend-editor-error-loading' ) );\n\t\t\t\t$el.removeClass( 'overlay-loading' );\n\t\t\t} );\n\t},\n\n\t/**\n\t * Loads a {VisualEditorOverlay} and replaces the existing EditorOverlay with it\n\t * based on the current option values.\n\t * @memberof EditorOverlay\n\t * @instance\n\t * @private\n\t * @param {Object} options Object passed to the constructor\n\t */\n\t_switchToVisualEditor: function ( options ) {\n\t\tvar self = this;\n\t\tthis.log( {\n\t\t\taction: 'abort',\n\t\t\ttype: 'switchnochange',\n\t\t\tmechanism: 'navigate'\n\t\t} );\n\t\t// Save a user setting indicating that this user prefers using the VisualEditor\n\t\tmw.storage.set( 'preferredEditor', 'VisualEditor' );\n\t\t// Load the VisualEditor and replace the SourceEditor overlay with it\n\t\tthis.showSpinner();\n\t\tthis.$content.hide();\n\t\tmw.loader.using( 'ext.visualEditor.targetLoader' ).then( function () {\n\t\t\tmw.libs.ve.targetLoader.addPlugin( 'mobile.editor.ve' );\n\t\t\treturn mw.libs.ve.targetLoader.loadModules( 'visual' );\n\t\t} ).then(\n\t\t\tfunction () {\n\t\t\t\toptions.EditorOverlay = EditorOverlay;\n\t\t\t\toptions.switched = true;\n\t\t\t\tself.hideSpinner();\n\t\t\t\t// Unset classes from other editor\n\t\t\t\tdelete options.className;\n\t\t\t\tself.switching = true;\n\t\t\t\tself.overlayManager.replaceCurrent( new VisualEditorOverlay( options ) );\n\t\t\t\tself.switching = false;\n\t\t\t},\n\t\t\tfunction () {\n\t\t\t\tself.hideSpinner();\n\t\t\t\tself.$content.show();\n\t\t\t\t// FIXME: We should show an error notification, but right now toast\n\t\t\t\t// notifications are not dismissible when shown within the editor.\n\t\t\t}\n\t\t);\n\t},\n\n\t/**\n\t * Reveals an abuse filter panel inside the view.\n\t * @memberof EditorOverlay\n\t * @instance\n\t * @private\n\t * @param {string} type The type of alert, e.g. 'warning' or 'disallow'\n\t * @param {string} message Message to show in the AbuseFilter overlay\n\t */\n\t_showAbuseFilter: function ( type, message ) {\n\t\tthis.abuseFilterPanel.show( type, message );\n\t\tthis.showHidden( '.save-header' );\n\t\t// disable continue and save buttons, reenabled when user changes content\n\t\tthis.$el.find( '.continue, .submit' ).prop( 'disabled', this.abuseFilterPanel.isDisallowed );\n\t},\n\n\t/**\n\t * Executed when the editor clicks the save/publish button. Handles logging and submitting\n\t * the save action to the editor API.\n\t * @inheritdoc\n\t * @memberof EditorOverlay\n\t * @instance\n\t */\n\tonSaveBegin: function () {\n\t\tvar self = this,\n\t\t\toptions = {\n\t\t\t\tsummary: this.$el.find( '.summary' ).val()\n\t\t\t};\n\n\t\tif ( self.sectionLine !== '' ) {\n\t\t\toptions.summary = '/* ' + self.sectionLine + ' */' + options.summary;\n\t\t}\n\t\tEditorOverlayBase.prototype.onSaveBegin.apply( this, arguments );\n\t\tif ( this.confirmAborted ) {\n\t\t\treturn;\n\t\t}\n\t\tif ( this.captchaId ) {\n\t\t\toptions.captchaId = this.captchaId;\n\t\t\toptions.captchaWord = this.$el.find( '.captcha-word' ).val();\n\t\t}\n\n\t\tthis.showHidden( '.saving-header' );\n\n\t\tthis.gateway.save( options )\n\t\t\t.then( function () {\n\t\t\t\tvar title = self.options.title;\n\t\t\t\t// Special case behaviour of main page\n\t\t\t\tif ( mw.config.get( 'wgIsMainPage' ) ) {\n\t\t\t\t\t// FIXME: Blocked on T189173\n\t\t\t\t\t// eslint-disable-next-line no-restricted-properties\n\t\t\t\t\twindow.location = mw.util.getUrl( title );\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tself.onSaveComplete();\n\t\t\t}, function ( data ) {\n\t\t\t\tself.onSaveFailure( data );\n\t\t\t} );\n\t},\n\n\t/**\n\t * Executed when page save fails. Handles error display and bookkeeping,\n\t * passes logging duties to the parent.\n\t * @inheritdoc\n\t * @memberof EditorOverlay\n\t * @instance\n\t */\n\tonSaveFailure: function ( data ) {\n\t\tvar heading, msg;\n\n\t\tif ( data.type === 'captcha' ) {\n\t\t\tthis.captchaId = data.details.id;\n\t\t\tthis.handleCaptcha( data.details );\n\t\t} else if ( data.type === 'abusefilter' ) {\n\t\t\tthis._showAbuseFilter( data.details.type, data.details.message );\n\t\t} else {\n\t\t\tmsg = saveFailureMessage( data );\n\t\t\tif ( data.type === 'readonly' ) {\n\t\t\t\theading = mw.msg( 'apierror-readonly' );\n\t\t\t}\n\n\t\t\tif ( msg || heading ) {\n\t\t\t\tthis.reportError( msg, heading );\n\t\t\t\tthis.showHidden( '.save-header, .save-panel' );\n\t\t\t}\n\t\t}\n\n\t\tEditorOverlayBase.prototype.onSaveFailure.apply( this, arguments );\n\t},\n\n\t/**\n\t * Checks whether the existing content has changed.\n\t * @memberof EditorOverlay\n\t * @instance\n\t * @return {boolean}\n\t */\n\thasChanged: function () {\n\t\treturn this.gateway.hasChanged;\n\t}\n} );\n\nmodule.exports = EditorOverlay;\n","var Overlay = require( '../mobile.startup/Overlay' ),\n\tutil = require( '../mobile.startup/util' ),\n\tPageGateway = require( '../mobile.startup/PageGateway' ),\n\tIcon = require( '../mobile.startup/Icon' ),\n\ttoast = require( '../mobile.startup/toast' ),\n\tsaveFailureMessage = require( './saveFailureMessage' ),\n\tmfExtend = require( '../mobile.startup/mfExtend' ),\n\tMessageBox = require( '../mobile.startup/MessageBox' ),\n\tmwUser = mw.user;\n\n/**\n * 'Edit' button\n * @param {OO.ui.ToolGroup} toolGroup\n * @param {Object} config\n */\nfunction EditVeTool( toolGroup, config ) {\n\tconfig = config || {};\n\tconfig.classes = [ 'visual-editor' ];\n\tEditVeTool.super.call( this, toolGroup, config );\n}\nOO.inheritClass( EditVeTool, OO.ui.Tool );\n\nEditVeTool.static.name = 'editVe';\nEditVeTool.static.icon = 'edit';\nEditVeTool.static.group = 'editorSwitcher';\nEditVeTool.static.title = mw.msg( 'mobile-frontend-editor-switch-visual-editor' );\n/**\n * click handler\n * @memberof EditVeTool\n * @instance\n */\nEditVeTool.prototype.onSelect = function () {\n\t// will be overridden later\n};\n/**\n * Toolbar update state handler.\n * @memberof EditVeTool\n * @instance\n */\nEditVeTool.prototype.onUpdateState = function () {\n\t// do nothing\n};\n\n/**\n * Base class for EditorOverlay\n * @class EditorOverlayBase\n * @extends Overlay\n * @uses Icon\n * @uses user\n * @param {Object} params Configuration options\n * @param {number|null} params.editCount of user\n */\nfunction EditorOverlayBase( params ) {\n\tvar self = this,\n\t\toptions = util.extend(\n\t\t\ttrue,\n\t\t\t{\n\t\t\t\tclassName: 'overlay editor-overlay',\n\t\t\t\tisBorderBox: false\n\t\t\t},\n\t\t\tparams,\n\t\t\t{\n\t\t\t\tevents: util.extend(\n\t\t\t\t\t{\n\t\t\t\t\t\t'click .back': 'onClickBack',\n\t\t\t\t\t\t'click .continue': 'onClickContinue',\n\t\t\t\t\t\t'click .submit': 'onClickSubmit'\n\t\t\t\t\t},\n\t\t\t\t\tparams.events\n\t\t\t\t)\n\t\t\t}\n\t\t);\n\n\tif ( options.isNewPage ) {\n\t\toptions.placeholder = mw.msg( 'mobile-frontend-editor-placeholder-new-page', mwUser );\n\t}\n\t// change the message to request a summary when not in article namespace\n\tif ( mw.config.get( 'wgNamespaceNumber' ) !== 0 ) {\n\t\toptions.summaryRequestMsg = mw.msg( 'mobile-frontend-editor-summary' );\n\t}\n\tthis.pageGateway = new PageGateway( options.api );\n\tthis.editCount = options.editCount;\n\tthis.isNewPage = options.isNewPage;\n\tthis.isNewEditor = options.editCount === 0;\n\tthis.sectionId = options.sectionId;\n\t// FIXME: Pass this in via options rather than accessing mw.config\n\tthis.config = mw.config.get( 'wgMFEditorOptions' );\n\tthis.sessionId = options.sessionId;\n\tthis.overlayManager = options.overlayManager;\n\tthis.allowCloseWindow = mw.confirmCloseWindow( {\n\t\t// Returns true if content has changed\n\t\ttest: function () {\n\t\t\t// Check if content has changed\n\t\t\treturn self.hasChanged();\n\t\t},\n\n\t\t// Message to show the user, if content has changed\n\t\tmessage: mw.msg( 'mobile-frontend-editor-cancel-confirm' ),\n\t\t// Event namespace\n\t\tnamespace: 'editwarning'\n\t} );\n\n\tOverlay.call( this, options );\n}\n\nmfExtend( EditorOverlayBase, Overlay, {\n\t/**\n\t * @memberof EditorOverlayBase\n\t * @instance\n\t * @mixes Overlay#defaults\n\t * @property {Object} defaults Default options hash.\n\t * @property {OverlayManager} defaults.overlayManager instance\n\t * @property {mw.Api} defaults.api to interact with\n\t * @property {boolean} defaults.hasToolbar Whether the editor has a toolbar or not. When\n\t *  disabled a header will be show instead.\n\t * @property {string} defaults.continueMsg Caption for the next button on edit form\n\t * which takes you to the screen that shows a preview and license information.\n\t * @property {string} defaults.cancelMsg Caption for cancel button on edit form.\n\t * @property {string} defaults.closeMsg Caption for a button that takes you back to editing\n\t * from edit preview screen.\n\t * @property {string} defaults.summaryRequestMsg Header above edit summary input field\n\t * asking the user to summarize the changes they made to the page.\n\t * @property {string} defaults.summaryMsg A placeholder with examples for the summary input\n\t * field asking user what they changed.\n\t * @property {string} defaults.placeholder Placeholder text for empty sections.\n\t * @property {string} defaults.waitMsg Text that displays while a page edit is being saved.\n\t * @property {string} defaults.waitIcon HTML of the icon that displays while a page edit\n\t * is being saved.\n\t * @property {string} defaults.captchaMsg Placeholder for captcha input field.\n\t * @property {string} defaults.captchaTryAgainMsg A message shown when user enters\n\t * wrong CAPTCHA and a new one is displayed.\n\t * @property {string} defaults.switchMsg Label for button that allows the user\n\t * to switch between two different editing interfaces.\n\t * @property {string} defaults.licenseMsg Text and link of the license,\n\t * under which this contribution will be released to inform the user.\n\t */\n\tdefaults: util.extend( {}, Overlay.prototype.defaults, {\n\t\thasToolbar: false,\n\t\tcontinueMsg: mw.msg( 'mobile-frontend-editor-continue' ),\n\t\tcancelMsg: mw.msg( 'mobile-frontend-editor-cancel' ),\n\t\tcloseMsg: mw.msg( 'mobile-frontend-editor-keep-editing' ),\n\t\tsummaryRequestMsg: mw.msg( 'mobile-frontend-editor-summary-request' ),\n\t\tsummaryMsg: mw.msg( 'mobile-frontend-editor-summary-placeholder' ),\n\t\tplaceholder: mw.msg( 'mobile-frontend-editor-placeholder' ),\n\t\twaitMsg: mw.msg( 'mobile-frontend-editor-wait' ),\n\t\t// icons.spinner can't be used,\n\t\t// the spinner class changes to display:none in onStageChanges\n\t\twaitIcon: new Icon( {\n\t\t\tname: 'spinner',\n\t\t\tadditionalClassNames: 'savespinner loading'\n\t\t} ).toHtmlString(),\n\t\tcaptchaMsg: mw.msg( 'mobile-frontend-account-create-captcha-placeholder' ),\n\t\tcaptchaTryAgainMsg: mw.msg( 'mobile-frontend-editor-captcha-try-again' ),\n\t\tswitchMsg: mw.msg( 'mobile-frontend-editor-switch-editor' ),\n\t\tconfirmMsg: mw.msg( 'mobile-frontend-editor-cancel-confirm' ),\n\t\tlicenseMsg: undefined\n\t} ),\n\t/**\n\t * @inheritdoc\n\t * @memberof EditorOverlayBase\n\t * @instance\n\t */\n\ttemplatePartials: util.extend( {}, Overlay.prototype.templatePartials, {\n\t\teditHeader: mw.template.get( 'mobile.editor.overlay', 'editHeader.hogan' ),\n\t\tpreviewHeader: mw.template.get( 'mobile.editor.overlay', 'previewHeader.hogan' ),\n\t\tsaveHeader: mw.template.get( 'mobile.editor.overlay', 'saveHeader.hogan' )\n\t} ),\n\t/**\n\t * @inheritdoc\n\t * @memberof EditorOverlayBase\n\t * @instance\n\t */\n\ttemplate: mw.template.get( 'mobile.editor.overlay', 'EditorOverlayBase.hogan' ),\n\t/**\n\t * @memberof EditorOverlayBase\n\t * @instance\n\t */\n\tsectionId: '',\n\t/**\n\t * Logs an event to http://meta.wikimedia.org/wiki/Schema:EditAttemptStep\n\t * @memberof EditorOverlayBase\n\t * @instance\n\t * @param {Object} data\n\t */\n\tlog: function ( data ) {\n\t\tmw.track( 'mf.schemaEditAttemptStep', util.extend( data, {\n\t\t\t// eslint-disable-next-line camelcase\n\t\t\teditor_interface: this.editor,\n\t\t\t// eslint-disable-next-line camelcase\n\t\t\tediting_session_id: this.sessionId\n\t\t} ) );\n\t},\n\n\t/**\n\t * If this is a new article, require confirmation before saving.\n\t * @memberof EditorOverlayBase\n\t * @instance\n\t * @return {boolean} The user confirmed saving\n\t */\n\tconfirmSave: function () {\n\t\tif ( this.isNewPage &&\n\t\t\t// TODO: Replace with an OOUI dialog\n\t\t\t!window.confirm( mw.msg( 'mobile-frontend-editor-new-page-confirm', mwUser ) )\n\t\t) {\n\t\t\treturn false;\n\t\t} else {\n\t\t\treturn true;\n\t\t}\n\t},\n\t/**\n\t * Executed when page save is complete. Handles reloading the page, showing toast\n\t * messages.\n\t * @memberof EditorOverlayBase\n\t * @instance\n\t */\n\tonSaveComplete: function () {\n\t\tvar msg,\n\t\t\t$window = util.getWindow(),\n\t\t\ttitle = this.options.title,\n\t\t\tself = this;\n\n\t\tthis.saved = true;\n\n\t\t// FIXME: use generic method for following 3 lines\n\t\tthis.pageGateway.invalidatePage( title );\n\n\t\tif ( this.isNewPage ) {\n\t\t\tmsg = mw.msg( 'mobile-frontend-editor-success-new-page' );\n\t\t} else if ( this.isNewEditor ) {\n\t\t\tmsg = mw.msg( 'mobile-frontend-editor-success-landmark-1' );\n\t\t} else {\n\t\t\tmsg = mw.msg( 'mobile-frontend-editor-success' );\n\t\t}\n\t\ttoast.showOnPageReload( msg, { type: 'success' } );\n\n\t\t// Ensure we don't lose this event when logging\n\t\tthis.log( {\n\t\t\taction: 'saveSuccess'\n\t\t} );\n\t\tif ( self.sectionId ) {\n\t\t\t// Ideally we'd want to do this via replaceState (see T189173)\n\t\t\t// eslint-disable-next-line no-restricted-properties\n\t\t\twindow.location.hash = '#' + self.sectionId;\n\t\t} else {\n\t\t\t// Cancel the hash fragment\n\t\t\t// otherwise clicking back after a save will take you back to the editor.\n\t\t\t// We avoid calling the hide method of the overlay here as this can be asynchronous\n\t\t\t// and may conflict with the window.reload call below.\n\t\t\t// eslint-disable-next-line no-restricted-properties\n\t\t\twindow.location.hash = '#';\n\t\t}\n\n\t\t$window.off( 'beforeunload.mfeditorwarning' );\n\n\t\t// Note the \"#\" may be in the URL.\n\t\t// If so, using window.location alone will not reload the page\n\t\t// we need to forcefully refresh\n\t\t// eslint-disable-next-line no-restricted-properties\n\t\twindow.location.reload();\n\t},\n\t/**\n\t * Executed when page save fails. Handles logging the error. Subclasses\n\t * should display error messages as appropriate.\n\t * @memberof EditorOverlayBase\n\t * @instance\n\t * @param {Object} data Details about the failure, from EditorGateway.parseSaveError\n\t */\n\tonSaveFailure: function ( data ) {\n\t\tvar key = data && data.details && data.details.code,\n\t\t\ttypeMap = {\n\t\t\t\teditconflict: 'editConflict',\n\t\t\t\twasdeleted: 'editPageDeleted',\n\t\t\t\t'abusefilter-disallowed': 'extensionAbuseFilter',\n\t\t\t\tcaptcha: 'extensionCaptcha',\n\t\t\t\tspamprotectiontext: 'extensionSpamBlacklist',\n\t\t\t\t'titleblacklist-forbidden-edit': 'extensionTitleBlacklist'\n\t\t\t};\n\n\t\tif ( data.type === 'captcha' ) {\n\t\t\tkey = 'captcha';\n\t\t}\n\n\t\tthis.log( {\n\t\t\taction: 'saveFailure',\n\t\t\tmessage: saveFailureMessage( data ),\n\t\t\ttype: typeMap[key] || 'responseUnknown'\n\t\t} );\n\t},\n\t/**\n\t * Report load errors back to the user. Silently record the error using EventLogging.\n\t * @memberof EditorOverlayBase\n\t * @instance\n\t * @param {string} text Text of message to display to user\n\t * @param {string} heading heading text to display to user\n\t */\n\treportError: function ( text, heading ) {\n\t\tvar errorNotice = new MessageBox( {\n\t\t\tclassName: 'errorbox',\n\t\t\tmsg: text,\n\t\t\theading: heading\n\t\t} );\n\t\tthis.$errorNoticeContainer.html( errorNotice.$el );\n\t},\n\thideErrorNotice: function () {\n\t\tthis.$errorNoticeContainer.empty();\n\t},\n\t/**\n\t * Prepares the penultimate screen before saving.\n\t * Expects to be overridden by child class.\n\t * @memberof EditorOverlayBase\n\t * @instance\n\t */\n\tonStageChanges: function () {\n\t\tthis.showHidden( '.save-header, .save-panel' );\n\t\tthis.log( {\n\t\t\taction: 'saveIntent'\n\t\t} );\n\t\t// Scroll to the top of the page, so that the summary input is visible\n\t\t// (even if overlay was scrolled down when editing) and weird iOS header\n\t\t// problems are avoided (header position not updating to the top of the\n\t\t// screen, instead staying lower until a subsequent scroll event).\n\t\twindow.scrollTo( 0, 1 );\n\t},\n\t/**\n\t * Executed when the editor clicks the save button. Expects to be overridden by child\n\t * class. Checks if the save needs to be confirmed.\n\t * @memberof EditorOverlayBase\n\t * @instance\n\t */\n\tonSaveBegin: function () {\n\t\tthis.confirmAborted = false;\n\t\tthis.hideErrorNotice();\n\t\t// Ask for confirmation in some cases\n\t\tif ( !this.confirmSave() ) {\n\t\t\tthis.confirmAborted = true;\n\t\t\treturn;\n\t\t}\n\t\tthis.log( {\n\t\t\taction: 'saveAttempt'\n\t\t} );\n\t},\n\t/**\n\t * @inheritdoc\n\t * @memberof EditorOverlayBase\n\t * @instance\n\t */\n\tpostRender: function () {\n\t\t// log edit attempt\n\t\t// TODO: if VE/NWE become the default, or even loadable-by-URL, this\n\t\t// logging needs to be moved into the individual overlays, because postRender\n\t\t// for VE still wouldn't technically be 'ready'.\n\t\tthis.log( {\n\t\t\taction: 'ready'\n\t\t} );\n\t\tthis.log( {\n\t\t\taction: 'loaded'\n\t\t} );\n\n\t\t// decide what happens, when the user clicks the continue button\n\t\tif ( this.config.skipPreview ) {\n\t\t\t// skip the preview and save the changes\n\t\t\tthis.nextStep = 'onSaveBegin';\n\t\t\tthis.$el.find( '.continue' ).text( this.defaults.saveMsg );\n\t\t} else {\n\t\t\t// default: show the preview step\n\t\t\tthis.nextStep = 'onStageChanges';\n\t\t}\n\t\tthis.$errorNoticeContainer = this.$el.find( '#error-notice-container' );\n\n\t\tOverlay.prototype.postRender.apply( this );\n\n\t\tthis.showHidden( '.initial-header' );\n\t},\n\tshow: function () {\n\t\tthis.saved = false;\n\t\tOverlay.prototype.show.call( this );\n\n\t\t// Inform other interested code that the editor has loaded\n\t\tmw.hook( 'mobileFrontend.editorOpened' ).fire( this.editor );\n\t},\n\t/**\n\t * Back button click handler\n\t * @memberof EditorOverlayBase\n\t * @instance\n\t */\n\tonClickBack: function () {},\n\t/**\n\t * Submit button click handler\n\t * @memberof EditorOverlayBase\n\t * @instance\n\t */\n\tonClickSubmit: function () {\n\t\tthis.onSaveBegin();\n\t},\n\t/**\n\t * Continue button click handler\n\t * @memberof EditorOverlayBase\n\t * @instance\n\t */\n\tonClickContinue: function () {\n\t\tthis[this.nextStep]();\n\t},\n\t/**\n\t * @inheritdoc\n\t * @memberof EditorOverlayBase\n\t * @instance\n\t * @return {boolean|jQuery.Promise} Boolean, or promise resolving with a boolean\n\t */\n\thide: function () {\n\t\tvar windowManager,\n\t\t\tself = this;\n\t\tif ( this.hasChanged() ) {\n\t\t\twindowManager = OO.ui.getWindowManager();\n\t\t\twindowManager.addWindows( [ new mw.widgets.AbandonEditDialog() ] );\n\t\t\treturn windowManager.openWindow( 'abandonedit' )\n\t\t\t\t.closed.then( function ( data ) {\n\t\t\t\t\tif ( data && data.action === 'discard' ) {\n\t\t\t\t\t\t// log abandonment\n\t\t\t\t\t\tself.log( {\n\t\t\t\t\t\t\taction: 'abort',\n\t\t\t\t\t\t\tmechanism: 'cancel',\n\t\t\t\t\t\t\ttype: 'abandon'\n\t\t\t\t\t\t} );\n\t\t\t\t\t\tself.allowCloseWindow.release();\n\t\t\t\t\t\tmw.hook( 'mobileFrontend.editorClosed' ).fire();\n\t\t\t\t\t\tOverlay.prototype.hide.call( self );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t}\n\t\tif ( !this.switching && !this.saved ) {\n\t\t\t// log leaving without changes\n\t\t\tthis.log( {\n\t\t\t\taction: 'abort',\n\t\t\t\tmechanism: 'cancel',\n\t\t\t\t// if this is VE, hasChanged will be false because the Surface has\n\t\t\t\t// already been destroyed (which is good because it stops us\n\t\t\t\t// double-showing the abandon changes dialog above)... but we can\n\t\t\t\t// test whether there *were* changes for logging purposes by\n\t\t\t\t// examining the target:\n\t\t\t\ttype: ( this.target && this.target.edited ) ? 'abandon' : 'nochange'\n\t\t\t} );\n\t\t}\n\t\tthis.allowCloseWindow.release();\n\t\tmw.hook( 'mobileFrontend.editorClosed' ).fire();\n\t\treturn Overlay.prototype.hide.call( self );\n\t},\n\t/**\n\t * Check, if the user should be asked if they really want to leave the page.\n\t * Returns false, if he hasn't made changes, otherwise true.\n\t * @memberof EditorOverlayBase\n\t * @instance\n\t * @param {boolean} [force] Whether this function should always return false\n\t * @return {boolean}\n\t */\n\tshouldConfirmLeave: function ( force ) {\n\t\tif ( force || !this.hasChanged() ) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\n\t},\n\t/**\n\t * Checks whether the state of the thing being edited as changed. Expects to be\n\t * implemented by child class.\n\t * @memberof EditorOverlayBase\n\t * @instance\n\t */\n\thasChanged: function () {},\n\t/**\n\t * Handles a failed save due to a CAPTCHA provided by ConfirmEdit extension.\n\t * @memberof EditorOverlayBase\n\t * @instance\n\t * @param {Object} details Details returned from the api.\n\t */\n\thandleCaptcha: function ( details ) {\n\t\tvar self = this,\n\t\t\t$input = this.$el.find( '.captcha-word' );\n\n\t\tif ( this.captchaShown ) {\n\t\t\t$input.val( '' );\n\t\t\t$input.attr( 'placeholder', this.options.captchaTryAgainMsg );\n\t\t\tsetTimeout( function () {\n\t\t\t\t$input.attr( 'placeholder', self.options.captchaMsg );\n\t\t\t}, 2000 );\n\t\t}\n\n\t\t// handle different mime types different\n\t\tif ( details.mime.indexOf( 'image/' ) === 0 ) {\n\t\t\t// image based CAPTCHA's like provided by FancyCaptcha, ReCaptcha or similar\n\t\t\tthis.$el.find( '.captcha-panel#question' ).detach();\n\t\t\tthis.$el.find( '.captcha-panel img' ).attr( 'src', details.url );\n\t\t} else {\n\t\t\t// not image based CAPTCHA.\n\t\t\tthis.$el.find( '.captcha-panel #image' ).detach();\n\t\t\tif ( details.mime.indexOf( 'text/html' ) === 0 ) {\n\t\t\t\t// handle mime type of HTML as HTML content (display as-is).\n\t\t\t\t// QuestyCaptcha now have default MIME type \"text/html\": see T147606\n\t\t\t\tthis.$el.find( '.captcha-panel #question' ).html( details.question );\n\t\t\t} else {\n\t\t\t\t// handle mime types\n\t\t\t\t// (other than image based ones and HTML based ones)\n\t\t\t\t// as plain text by default.\n\t\t\t\t// e.g. MathCaptcha (solve a math formula) or\n\t\t\t\t// SimpleCaptcha (simple math formula)\n\t\t\t\tthis.$el.find( '.captcha-panel #question' ).text( details.question );\n\t\t\t}\n\t\t}\n\n\t\tthis.showHidden( '.save-header, .captcha-panel' );\n\t\tthis.captchaShown = true;\n\t}\n} );\n\nmodule.exports = EditorOverlayBase;\n","/* global ve */\nvar EditorOverlayBase = require( './EditorOverlayBase' ),\n\tEditorGateway = require( './EditorGateway' ),\n\tmfExtend = require( '../mobile.startup/mfExtend' ),\n\tutil = require( '../mobile.startup/util' );\n\n/**\n * Overlay for VisualEditor view\n * @class VisualEditorOverlay\n * @extends EditorOverlayBase\n *\n * @param {Object} options Configuration options\n * @param {EditorOverlay} options.EditorOverlay Class to use for standard\n *  Wikitext editor. It must be passed in explicitly to avoid a cyclic\n *  dependency between VisualEdtiorOverlay and EditorOverlay\n */\nfunction VisualEditorOverlay( options ) {\n\tthis.applyHeaderOptions( options, true );\n\tEditorOverlayBase.call( this,\n\t\tutil.extend( {\n\t\t\tisBorderBox: false,\n\t\t\tclassName: 'overlay editor-overlay editor-overlay-ve'\n\t\t}, options )\n\t);\n\tthis.EditorOverlay = options.EditorOverlay;\n\tthis.isNewPage = options.isNewPage;\n\n\t// Gateway present for a few utility purposes; the VE articletarget\n\t// handles the actual API calls separately\n\tthis.gateway = new EditorGateway( {\n\t\tapi: options.api,\n\t\ttitle: options.title,\n\t\tsectionId: options.sectionId,\n\t\toldId: options.oldId,\n\t\tisNewPage: options.isNewPage\n\t} );\n}\n\nmfExtend( VisualEditorOverlay, EditorOverlayBase, {\n\t/**\n\t * @inheritdoc\n\t * @memberof VisualEditorOverlay\n\t * @instance\n\t */\n\ttemplatePartials: util.extend( {}, EditorOverlayBase.prototype.templatePartials, {\n\t\teditHeader: mw.template.get( 'mobile.editor.overlay', 'toolbarVE.hogan' ),\n\t\tcontent: mw.template.get( 'mobile.editor.overlay', 'contentVE.hogan' )\n\t} ),\n\t/**\n\t * @memberof VisualEditorOverlay\n\t * @instance\n\t */\n\teditor: 'visualeditor',\n\t/**\n\t * Set options that apply specifically to VisualEditorOverlay but not\n\t * EditorOverlay so that an EditorOverlay instance can be created effortlessly.\n\t * FIXME: Must be smarter way to do this.\n\t * @memberof VisualEditorOverlay\n\t * @instance\n\t * @param {Object} options Configuration options\n\t * @param {boolean} isVE whether the options are being generated for a VisualEditorOverlay\n\t *  or a EditorOverlay\n\t */\n\tapplyHeaderOptions: function ( options, isVE ) {\n\t\t// Set things that are known to be true.\n\t\toptions.hasToolbar = isVE;\n\t\toptions.isVisualEditor = isVE;\n\t},\n\t/**\n\t * Destroy the existing VisualEditor target.\n\t * @memberof VisualEditorOverlay\n\t * @instance\n\t */\n\tdestroyTarget: function () {\n\t\tif ( this.target ) {\n\t\t\tthis.target.destroy();\n\t\t\tthis.target = null;\n\t\t}\n\t},\n\t/**\n\t * @inheritdoc\n\t * @memberof VisualEditorOverlay\n\t * @instance\n\t */\n\tshow: function () {\n\t\tEditorOverlayBase.prototype.show.apply( this, arguments );\n\n\t\t// We don't use the default spinner. Instead, rely on the progressbar from init/editor.js.\n\t\tif ( !this.options.switched ) {\n\t\t\tthis.hideSpinner();\n\t\t\tthis.$el.addClass( 'loading' );\n\t\t}\n\n\t\tthis.target = ve.init.mw.targetFactory.create( 'article', this, {\n\t\t\t$element: this.$el,\n\t\t\t// || null so that scrolling is not triggered for the lead (0) section\n\t\t\t// (which has no header to scroll to)\n\t\t\tsection: this.options.sectionId || null\n\t\t} );\n\t\tthis.target.once( 'surfaceReady', function () {\n\t\t\tthis.emit( 'editor-loaded' );\n\t\t\tthis.$el.removeClass( 'loading' );\n\t\t}.bind( this ) );\n\t\tthis.target.load( this.options.dataPromise );\n\t},\n\t/**\n\t * @inheritdoc\n\t * @memberof VisualEditorOverlay\n\t * @instance\n\t */\n\thide: function () {\n\t\tvar overlay = this,\n\t\t\tretval = EditorOverlayBase.prototype.hide.apply( this, arguments );\n\t\tif ( retval === true ) {\n\t\t\tthis.destroyTarget();\n\t\t} else if ( retval && retval.then ) {\n\t\t\tretval.then( function ( hide ) {\n\t\t\t\tif ( hide ) {\n\t\t\t\t\toverlay.destroyTarget();\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t\treturn retval;\n\t},\n\t/**\n\t * @inheritdoc\n\t * @memberof VisualEditorOverlay\n\t * @instance\n\t */\n\tonClickBack: function () {\n\t\tEditorOverlayBase.prototype.onClickBack.apply( this, arguments );\n\t\tthis.switchToEditor();\n\t},\n\n\t/**\n\t * Reveal the editing interface.\n\t * @memberof VisualEditorOverlay\n\t * @instance\n\t */\n\tswitchToEditor: function () {\n\t\tthis.showHidden( '.initial-header' );\n\t},\n\t/**\n\t * Loads an {EditorOverlay} and replaces the existing {VisualEditorOverlay}\n\t * @memberof VisualEditorOverlay\n\t * @instance\n\t */\n\tswitchToSourceEditor: function () {\n\t\tvar self = this,\n\t\t\tEditorOverlay = this.EditorOverlay;\n\t\tthis.log( {\n\t\t\taction: 'abort',\n\t\t\ttype: 'switchnochange',\n\t\t\tmechanism: 'navigate'\n\t\t} );\n\t\t// Save a user setting indicating that this user prefers using the SourceEditor\n\t\tmw.storage.set( 'preferredEditor', 'SourceEditor' );\n\t\tthis.showSpinner();\n\t\tthis.$el.find( '.surface' ).hide();\n\t\tself.hideSpinner();\n\t\tself.applyHeaderOptions( self.options, false );\n\t\t// Unset classes from other editor\n\t\tdelete self.options.className;\n\t\tself.switching = true;\n\t\tself.overlayManager.replaceCurrent( new EditorOverlay( self.options ) );\n\t\tself.switching = false;\n\t},\n\t/**\n\t * @inheritdoc\n\t * @memberof VisualEditorOverlay\n\t * @instance\n\t */\n\tonSaveComplete: function () {\n\t\tEditorOverlayBase.prototype.onSaveComplete.apply( this, arguments );\n\t\tthis.destroyTarget();\n\t},\n\t/**\n\t * @inheritdoc\n\t * @memberof VisualEditorOverlay\n\t * @instance\n\t */\n\thasChanged: function () {\n\t\treturn this.target &&\n\t\t\tthis.target.getSurface() &&\n\t\t\tthis.target.getSurface().getModel().hasBeenModified() &&\n\t\t\t// If we just saved, there's not really any changes, and the\n\t\t\t// target is going to be destroyed in one tick\n\t\t\t!this.saved;\n\t}\n} );\n\nmodule.exports = VisualEditorOverlay;\n","/**\n * Turn an API response on save failure into a details object\n * @param {Object|null} data API response data\n * @param {string} [code] Text status message from API\n * @return {Object} An object with `type` and `details` properties.\n * `type` is a string describing the type of error, `details` can be any\n * object (usually error message).\n*/\nfunction parseSaveError( data, code ) {\n\tvar warning;\n\tif ( code ) {\n\t\tswitch ( code ) {\n\t\t\tcase 'readonly':\n\t\t\t\treturn {\n\t\t\t\t\ttype: 'readonly',\n\t\t\t\t\tdetails: data.error\n\t\t\t\t};\n\t\t\tcase 'editconflict':\n\t\t\t\treturn {\n\t\t\t\t\ttype: 'editconflict',\n\t\t\t\t\tdetails: data.error\n\t\t\t\t};\n\t\t\tdefault:\n\t\t\t\treturn {\n\t\t\t\t\ttype: 'error',\n\t\t\t\t\tdetails: 'http'\n\t\t\t\t};\n\t\t}\n\t}\n\tif ( data ) {\n\t\tif ( data.error ) {\n\t\t\t// Edit API error\n\t\t\treturn {\n\t\t\t\ttype: 'error',\n\t\t\t\tdetails: data.error.code\n\t\t\t};\n\t\t} else if ( data.edit && data.edit.captcha ) {\n\t\t\t// CAPTCHAs\n\t\t\treturn {\n\t\t\t\ttype: 'captcha',\n\t\t\t\tdetails: data.edit.captcha\n\t\t\t};\n\t\t} else if ( data.edit && data.edit.code ) {\n\t\t\tcode = data.edit.code;\n\t\t\twarning = data.edit.warning;\n\n\t\t\t// FIXME: AbuseFilter should have more consistent API responses\n\t\t\tif ( /^abusefilter-warning/.test( code ) ) {\n\t\t\t\t// AbuseFilter warning\n\t\t\t\treturn {\n\t\t\t\t\ttype: 'abusefilter',\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\ttype: 'warning',\n\t\t\t\t\t\tmessage: warning\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t} else if ( /^abusefilter-disallow/.test( code ) ) {\n\t\t\t\t// AbuseFilter disallow\n\t\t\t\treturn {\n\t\t\t\t\ttype: 'abusefilter',\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\ttype: 'disallow',\n\t\t\t\t\t\tmessage: warning\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t} else if ( /^abusefilter/.test( code ) ) {\n\t\t\t\t// AbuseFilter other\n\t\t\t\treturn {\n\t\t\t\t\ttype: 'abusefilter',\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\ttype: 'other',\n\t\t\t\t\t\tmessage: warning\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}\n\t\t\t// other errors\n\t\t\treturn {\n\t\t\t\ttype: 'error',\n\t\t\t\tdetails: code\n\t\t\t};\n\t\t}\n\t}\n\treturn {\n\t\ttype: 'error',\n\t\tdetails: 'unknown'\n\t};\n}\nmodule.exports = parseSaveError;\n","/**\n * Build a save failure message from the API response\n * @param {Object} data Details about the failure, from EditorGateway.parseSaveError\n * @return {string} message describing the failure for display to the user\n */\nmodule.exports = function saveFailureMessage( data ) {\n\tvar key = data && data.details && data.details.code,\n\t\t// When save failed with one of these error codes, the returned\n\t\t// message in response.error.info will be forwarded to the user.\n\t\t// FIXME: This shouldn't be needed when info texts are all localized.\n\t\twhitelistedErrorInfo = [\n\t\t\t'blocked',\n\t\t\t'autoblocked'\n\t\t];\n\tif ( data.type === 'readonly' ) {\n\t\treturn data.details.readonlyreason;\n\t}\n\tif ( key === 'editconflict' ) {\n\t\treturn mw.msg( 'mobile-frontend-editor-error-conflict' );\n\t} else if ( whitelistedErrorInfo.indexOf( key ) > -1 ) {\n\t\treturn data.error.info;\n\t}\n\treturn mw.msg( 'mobile-frontend-editor-error' );\n};\n","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","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","var View = require( '../mobile.startup/View' ),\n\tutil = require( '../mobile.startup/util' ),\n\tmfExtend = require( '../mobile.startup/mfExtend' ),\n\tIcon = require( '../mobile.startup/Icon' ),\n\ticons = require( '../mobile.startup/icons' ),\n\tButton = require( '../mobile.startup/Button' ),\n\tdetailsButton = new Button( {\n\t\tlabel: mw.msg( 'mobile-frontend-media-details' ),\n\t\tadditionalClassNames: 'button',\n\t\tprogressive: true\n\t} ),\n\tslideLeftButton = new Icon( {\n\t\trotation: 90,\n\t\tname: 'arrow-invert'\n\t} ),\n\tslideRightButton = new Icon( {\n\t\trotation: -90,\n\t\tname: 'arrow-invert'\n\t} ),\n\tLoadErrorMessage = require( './LoadErrorMessage' ),\n\tImageGateway = require( './ImageGateway' ),\n\t// FIXME: mw.loader.require is a private function but there's no other way to get hold of\n\t// this right now using require will cause webpack to resolve it\n\t// Can be rewritten to mw.router when https://gerrit.wikimedia.org/r/#/c/mediawiki/core/+/482732 has been merged\n\trouter = mw.loader.require( 'mediawiki.router' );\n\n/**\n * Displays images in full screen overlay\n * @class ImageCarousel\n * @extends View\n * @param {Object} options Configuration options\n * @param {OO.EventEmitter} options.eventBus Object used to listen for resize:throttled events\n */\nfunction ImageCarousel( options ) {\n\tthis.gateway = options.gateway || new ImageGateway( {\n\t\tapi: options.api\n\t} );\n\tthis.router = options.router || router;\n\tthis.eventBus = options.eventBus;\n\n\tView.call(\n\t\tthis,\n\t\tutil.extend(\n\t\t\t{\n\t\t\t\tclassName: 'image-carousel',\n\t\t\t\tevents: {\n\t\t\t\t\t'click .image-wrapper': 'onToggleDetails',\n\t\t\t\t\t// Click tracking for table of contents so we can see if people interact with it\n\t\t\t\t\t'click .slider-button': 'onSlide'\n\t\t\t\t}\n\t\t\t},\n\t\t\toptions\n\t\t)\n\t);\n}\n\nmfExtend( ImageCarousel, View, {\n\t/**\n\t * @memberof ImageCarousel\n\t * @instance\n\t */\n\thideOnExitClick: false,\n\t/**\n\t * @memberof ImageCarousel\n\t * @instance\n\t */\n\ttemplate: mw.template.get( 'mobile.mediaViewer', 'ImageCarousel.hogan' ),\n\n\t/**\n\t * @memberof ImageCarousel\n\t * @instance\n\t * @mixes Overlay#defaults\n\t * @property {Object} defaults Default options hash.\n\t * @property {mw.Api} defaults.api instance of API to use\n\t * @property {string} defaults.licenseLinkMsg Link to license information in media viewer.\n\t * @property {Thumbnail[]} defaults.thumbnails a list of thumbnails to browse\n\t */\n\tdefaults: util.extend( {}, View.prototype.defaults, {\n\t\tlicenseLinkMsg: mw.msg( 'mobile-frontend-media-license-link' ),\n\t\tthumbnails: []\n\t} ),\n\t/**\n\t * Event handler for slide event\n\t * @memberof ImageCarousel\n\t * @instance\n\t * @param {jQuery.Event} ev\n\t */\n\tonSlide: function ( ev ) {\n\t\tvar\n\t\t\tnewImageCarousel,\n\t\t\tnextThumbnail = this.$el.find( ev.target ).closest( '.slider-button' ).data( 'thumbnail' ),\n\t\t\ttitle = nextThumbnail.options.filename;\n\n\t\tthis.router.navigateTo( null, {\n\t\t\tpath: '#/media/' + title,\n\t\t\tuseReplaceState: true\n\t\t} );\n\t\tthis.options.title = nextThumbnail.options.filename;\n\t\tnewImageCarousel = new ImageCarousel( this.options );\n\t\tthis.$el.replaceWith( newImageCarousel.$el );\n\t\tthis.$el = newImageCarousel.$el;\n\t},\n\t/**\n\t * @inheritdoc\n\t * @memberof ImageCarousel\n\t * @instance\n\t */\n\tpreRender: function () {\n\t\tvar self = this;\n\t\tthis.options.thumbnails.forEach( function ( thumbnail, i ) {\n\t\t\tif ( thumbnail.getFileName() === self.options.title ) {\n\t\t\t\tself.options.caption = thumbnail.getDescription();\n\t\t\t\tself.galleryOffset = i;\n\t\t\t}\n\t\t} );\n\t},\n\t/**\n\t * Setup the next and previous images to enable the user to arrow through\n\t * all images in the set of images given in thumbs.\n\t * @memberof ImageCarousel\n\t * @instance\n\t * @param {Array} thumbs A set of images, which are available\n\t * @private\n\t */\n\t_enableArrowImages: function ( thumbs ) {\n\t\tvar offset = this.galleryOffset,\n\t\t\tlastThumb, nextThumb;\n\n\t\tif ( this.galleryOffset === undefined ) {\n\t\t\t// couldn't find a suitable matching thumbnail so make\n\t\t\t// next slide start at beginning and previous slide be end\n\t\t\tlastThumb = thumbs[thumbs.length - 1];\n\t\t\tnextThumb = thumbs[0];\n\t\t} else {\n\t\t\t// identify last thumbnail\n\t\t\tlastThumb = thumbs[ offset === 0 ? thumbs.length - 1 : offset - 1 ];\n\t\t\tnextThumb = thumbs[ offset === thumbs.length - 1 ? 0 : offset + 1 ];\n\t\t}\n\n\t\tthis.$el.find( '.prev' ).data( 'thumbnail', lastThumb );\n\t\tthis.$el.find( '.next' ).data( 'thumbnail', nextThumb );\n\t},\n\t/**\n\t * Disables the possibility to arrow through all images of the page.\n\t * @memberof ImageCarousel\n\t * @instance\n\t * @private\n\t */\n\t_disableArrowImages: function () {\n\t\tthis.$el.find( '.prev, .next' ).remove();\n\t},\n\n\t/**\n\t * Handler for retry event which triggers when user tries to reload overlay\n\t * after a loading error.\n\t * @memberof ImageCarousel\n\t * @instance\n\t * @private\n\t */\n\t_handleRetry: function () {\n\t\t// A hacky way to simulate a reload of the overlay\n\t\tthis.router.emit( 'hashchange' );\n\t},\n\n\t/**\n\t * @inheritdoc\n\t * @memberof ImageCarousel\n\t * @instance\n\t */\n\tpostRender: function () {\n\t\tvar\n\t\t\t$img,\n\t\t\t$el = this.$el,\n\t\t\t$spinner = icons.spinner().$el,\n\t\t\tthumbs = this.options.thumbnails || [],\n\t\t\tself = this;\n\n\t\t/**\n\t\t * Display media load failure message\n\t\t * @method\n\t\t * @ignore\n\t\t */\n\t\tfunction showLoadFailMsg() {\n\t\t\tself.hasLoadError = true;\n\n\t\t\t$spinner.hide();\n\t\t\t// hide broken image if present\n\t\t\t$el.find( '.image img' ).hide();\n\n\t\t\t// show error message if not visible already\n\t\t\tif ( $el.find( '.load-fail-msg' ).length === 0 ) {\n\t\t\t\tnew LoadErrorMessage( { retryPath: self.router.getPath() } )\n\t\t\t\t\t.on( 'retry', self._handleRetry.bind( self ) )\n\t\t\t\t\t.prependTo( $el.find( '.image' ) );\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * Start image load transitions\n\t\t * @method\n\t\t * @ignore\n\t\t */\n\t\tfunction addImageLoadClass() {\n\t\t\t$img.addClass( 'image-loaded' );\n\t\t}\n\n\t\tif ( thumbs.length < 2 ) {\n\t\t\tthis._disableArrowImages();\n\t\t} else {\n\t\t\tthis._enableArrowImages( thumbs );\n\t\t}\n\n\t\tthis.$details = $el.find( '.image-details' );\n\t\t$el.find( '.image' ).append( $spinner );\n\n\t\tthis.$details.prepend( detailsButton.$el );\n\n\t\tthis.gateway.getThumb( self.options.title ).then( function ( data ) {\n\t\t\tvar author, url = data.descriptionurl + '#mw-jump-to-license';\n\n\t\t\t$spinner.hide();\n\n\t\t\tself.thumbWidth = data.thumbwidth;\n\t\t\tself.thumbHeight = data.thumbheight;\n\t\t\tself.imgRatio = data.thumbwidth / data.thumbheight;\n\n\t\t\t// We need to explicitly specify document for context param as jQuery 3\n\t\t\t// will create a new document for the element if the context is\n\t\t\t// undefined. If element is appended to active document, event handlers\n\t\t\t// can fire in both the active document and new document which can cause\n\t\t\t// insidious bugs.\n\t\t\t// (https://api.jquery.com/jquery.parsehtml/#entry-longdesc)\n\t\t\t$img = self.parseHTML( '<img>', document );\n\n\t\t\t// Remove the loader when the image is loaded or display load fail\n\t\t\t// message on failure\n\t\t\t//\n\t\t\t// Error event handler must be attached before error occurs\n\t\t\t// (https://api.jquery.com/error/#entry-longdesc)\n\t\t\t//\n\t\t\t// For the load event, it is more unclear what happens cross-browser when\n\t\t\t// the image is loaded from cache. It seems that a .complete check is\n\t\t\t// needed if attaching the load event after setting the src.\n\t\t\t// (http://stackoverflow.com/questions/910727/jquery-event-for-images-loaded#comment10616132_1110094)\n\t\t\t//\n\t\t\t// However, perhaps .complete check is not needed if attaching load\n\t\t\t// event prior to setting the image src\n\t\t\t// (https://stackoverflow.com/questions/12354865/image-onload-event-and-browser-cache#answer-12355031)\n\t\t\t$img.on( 'load', addImageLoadClass ).on( 'error', showLoadFailMsg );\n\t\t\t$img.attr( 'src', data.thumburl ).attr( 'alt', self.options.caption );\n\t\t\t$el.find( '.image' ).append( $img );\n\n\t\t\tself.$details.addClass( 'is-visible' );\n\t\t\tself._positionImage();\n\t\t\t$el.find( '.image-details a' ).attr( 'href', url );\n\t\t\tif ( data.extmetadata ) {\n\t\t\t\t// Add license information\n\t\t\t\tif ( data.extmetadata.LicenseShortName ) {\n\t\t\t\t\t$el.find( '.license a' )\n\t\t\t\t\t\t.text( data.extmetadata.LicenseShortName.value )\n\t\t\t\t\t\t.attr( 'href', url );\n\t\t\t\t}\n\t\t\t\t// Add author information\n\t\t\t\tif ( data.extmetadata.Artist ) {\n\t\t\t\t\t// Strip any tags\n\t\t\t\t\tauthor = data.extmetadata.Artist.value.replace( /<.*?>/g, '' );\n\t\t\t\t\t$el.find( '.license' ).prepend( author + ' &bull; ' );\n\t\t\t\t}\n\t\t\t}\n\t\t\tself.adjustDetails();\n\t\t}, function () {\n\t\t\t// retrieving image location failed so show load fail msg\n\t\t\tshowLoadFailMsg();\n\t\t} );\n\n\t\tthis.eventBus.on( 'resize:throttled', this._positionImage.bind( this ) );\n\t\tthis._positionImage();\n\t},\n\n\t/**\n\t * Event handler that toggles the details bar.\n\t * @memberof ImageCarousel\n\t * @instance\n\t */\n\tonToggleDetails: function () {\n\t\tif ( !this.hasLoadError ) {\n\t\t\tthis.$el.find( '.cancel, .slider-button' ).toggle();\n\t\t\tthis.$details.toggle();\n\t\t\tthis._positionImage();\n\t\t}\n\t},\n\t/**\n\t * Fit the image into the window if its dimensions are bigger than the window dimensions.\n\t * Compare window width to height ratio to that of image width to height when setting\n\t * image width or height.\n\t * @memberof ImageCarousel\n\t * @instance\n\t * @private\n\t */\n\t_positionImage: function () {\n\t\tvar detailsHeight, windowWidth, windowHeight, windowRatio, $img,\n\t\t\t$window = util.getWindow();\n\n\t\tthis.adjustDetails();\n\t\t// with a hidden details box we have a little bit more space, we just need to use it\n\t\tdetailsHeight = !this.$details.is( ':visible' ) ? 0 : this.$details.outerHeight();\n\t\twindowWidth = $window.width();\n\t\twindowHeight = $window.height() - detailsHeight;\n\t\twindowRatio = windowWidth / windowHeight;\n\t\t$img = this.$el.find( 'img' );\n\n\t\tif ( this.imgRatio > windowRatio ) {\n\t\t\tif ( windowWidth < this.thumbWidth ) {\n\t\t\t\t$img.css( {\n\t\t\t\t\twidth: windowWidth,\n\t\t\t\t\theight: 'auto'\n\t\t\t\t} );\n\t\t\t}\n\t\t} else {\n\t\t\tif ( windowHeight < this.thumbHeight ) {\n\t\t\t\t$img.css( {\n\t\t\t\t\twidth: 'auto',\n\t\t\t\t\theight: windowHeight\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\n\t\tthis.$el.find( '.image-wrapper' ).css( 'bottom', detailsHeight );\n\t\tthis.$el.find( '.slider-button.prev' ).append( slideLeftButton.$el );\n\t\tthis.$el.find( '.slider-button.next' ).append( slideRightButton.$el );\n\t},\n\n\t/**\n\t * Function to adjust the height of details section to not more than 50% of window height.\n\t * @memberof ImageCarousel\n\t * @instance\n\t */\n\tadjustDetails: function () {\n\t\tvar windowHeight = util.getWindow().height();\n\t\tif ( this.$el.find( '.image-details' ).height() > windowHeight * 0.50 ) {\n\t\t\tthis.$el.find( '.image-details' ).css( 'max-height', windowHeight * 0.50 );\n\t\t}\n\t}\n} );\n\nmodule.exports = ImageCarousel;\n","var sizeBuckets = [ 320, 640, 800, 1024, 1280, 1920, 2560, 2880 ],\n\tactionParams = require( './../mobile.startup/actionParams' ),\n\tutil = require( './../mobile.startup/util' );\n\n/**\n * Gets the first size larger than or equal to the provided size\n * @memberof ImageGateway\n * @param {number} size\n * @return {number}\n */\nfunction findSizeBucket( size ) {\n\tvar i = 0;\n\twhile ( size > sizeBuckets[i] && i < sizeBuckets.length - 1 ) {\n\t\t++i;\n\t}\n\treturn sizeBuckets[i];\n}\n\n/**\n * API for retrieving image thumbnails for a given page\n * @class ImageGateway\n *\n * @param {Object} options Configuration options\n * @property {mw.Api} options.api\n */\nfunction ImageGateway( options ) {\n\tthis._cache = {};\n\tthis.api = options.api;\n}\n/**\n * Get thumbnail via the API and cache it. Return the result from the cache if exists.\n * @param {string} title Url of image\n * @return {jQuery.Deferred} with the image info\n */\nImageGateway.prototype.getThumb = function ( title ) {\n\tvar cachedThumb = this._cache[title],\n\t\t$window = util.getWindow(),\n\t\timageSizeMultiplier = ( window.devicePixelRatio && window.devicePixelRatio > 1 ) ?\n\t\t\twindow.devicePixelRatio : 1;\n\n\tif ( !cachedThumb ) {\n\t\tthis._cache[title] = this.api.get( actionParams( {\n\t\t\tprop: 'imageinfo',\n\t\t\ttitles: title,\n\t\t\tiiprop: [ 'url', 'extmetadata' ],\n\t\t\t// request an image devicePixelRatio times bigger than the reported screen size\n\t\t\t// for retina displays and zooming\n\t\t\tiiurlwidth: findSizeBucket( $window.width() * imageSizeMultiplier ),\n\t\t\tiiurlheight: findSizeBucket( $window.height() * imageSizeMultiplier )\n\t\t} ) ).then( function ( resp ) {\n\t\t\t// imageinfo is undefined for missing pages.\n\t\t\tif ( resp.query && resp.query.pages &&\n\t\t\t\tresp.query.pages[0] && resp.query.pages[0].imageinfo ) {\n\t\t\t\treturn resp.query.pages[0].imageinfo[0];\n\t\t\t}\n\t\t\tthrow new Error( 'The API failed to return any pages matching the titles.' );\n\t\t} );\n\t}\n\n\treturn this._cache[title];\n};\n\nImageGateway._findSizeBucket = findSizeBucket;\nmodule.exports = ImageGateway;\n","var util = require( './../mobile.startup/util' ),\n\tmfExtend = require( './../mobile.startup/mfExtend' ),\n\tIcon = require( './../mobile.startup/Icon' ),\n\tView = require( './../mobile.startup/View' );\n\n/**\n * Shows the user a load failure message\n * @class LoadErrorMessage\n * @extends View\n * @fires LoadErrorMessage#retry\n *\n * @param {Object} options Configuration options\n */\nfunction LoadErrorMessage( options ) {\n\tif ( !options.retryPath ) {\n\t\tthrow new Error( '\\'retryPath\\' must be set in options param. Received: ' + options.retryPath );\n\t}\n\tView.call(\n\t\tthis,\n\t\t{ events: { 'click .load-fail-msg-link a': 'onRetry' } },\n\t\toptions\n\t);\n}\n\nmfExtend( LoadErrorMessage, View, {\n\ttemplate: mw.template.get( 'mobile.mediaViewer', 'LoadErrorMessage.hogan' ),\n\tisTemplateMode: true,\n\n\t/**\n\t\t* @inheritdoc\n\t\t* @cfg {Object} defaults Default options hash.\n\t\t* @cfg {string} defaults.icon HTML of the alert icon\n\t\t* @cfg {string} defaults.msgToUser Message shown when media load fails\n\t\t* @cfg {string} defaults.retryTxt Text of retry link\n\t\t* @memberof LoadErrorMessage\n\t\t* @instance\n\t\t*/\n\tdefaults: util.extend( {}, LoadErrorMessage.prototype.defaults, {\n\t\ticon: new Icon( {\n\t\t\tname: 'alert-invert',\n\t\t\tadditionalClassNames: 'load-fail-msg-icon'\n\t\t} ).toHtmlString(),\n\t\tmsgToUser: mw.msg( 'mobile-frontend-media-load-fail-message' ),\n\t\tretryTxt: mw.msg( 'mobile-frontend-media-load-fail-retry' )\n\t} ),\n\n\t/**\n\t * @inheritdoc\n\t * @memberof LoadErrorMessage\n\t * @instance\n\t */\n\tpostRender: function () {\n\t\tthis.$el.find( '.load-fail-msg-link a' ).attr( 'href', '#' + this.options.retryPath );\n\t},\n\n\t/**\n\t * Event handler for retry event\n\t * @param {jQuery.Event} ev\n\t * @return {boolean} Returns false to prevent default behavior for links and\n\t * stop the event from propagating\n\t * @memberof LoadErrorMessage\n\t * @instance\n\t */\n\tonRetry: function () {\n\t\t/**\n\t\t * Triggered when retry button is clicked.\n\t\t * @event LoadErrorMessage#retry\n\t\t */\n\t\tthis.emit( 'retry' );\n\n\t\treturn false;\n\t}\n} );\n\nmodule.exports = LoadErrorMessage;\n","/** @event */\nvar\n\tNEARBY_EVENT_POST_RENDER = 'Nearby-postRender',\n\tMessageBox = require( '../mobile.startup/MessageBox' ),\n\tNearbyGateway = require( './NearbyGateway' ),\n\tutil = require( '../mobile.startup/util' ),\n\tWatchstarPageList = require( '../mobile.startup/watchstar/WatchstarPageList.js' ),\n\tmfExtend = require( '../mobile.startup/mfExtend' );\n\n/**\n * List of nearby pages\n * @class Nearby\n * @uses NearbyGateway\n * @extends WatchstarPageList\n *\n * @param {Object} options Configuration options\n * @param {OO.EventEmitter} options.eventBus Object used to emit Nearby-postRender events\n * @param {Function} [options.onItemClick] Callback invoked when a result is\n *                                         clicked. Defaults to nop.\n */\nfunction Nearby( options ) {\n\tvar self = this,\n\t\t_super = WatchstarPageList;\n\n\tthis.range = options.range || mw.config.get( 'wgMFNearbyRange' ) || 1000;\n\tthis.source = options.source || 'nearby';\n\tthis.nearbyApi = new NearbyGateway( {\n\t\tapi: options.api\n\t} );\n\tthis.eventBus = options.eventBus;\n\n\tif ( options.errorType ) {\n\t\toptions.errorOptions = self._errorOptions( options.errorType );\n\t}\n\n\tthis.onItemClick = options.onItemClick;\n\n\t_super.apply( this, arguments );\n}\n\nmfExtend( Nearby, WatchstarPageList, {\n\t/**\n\t * @memberof Nearby\n\t * @instance\n\t */\n\terrorMessages: {\n\t\tempty: {\n\t\t\theading: mw.msg( 'mobile-frontend-nearby-noresults' ),\n\t\t\thasHeading: true,\n\t\t\tmsg: mw.msg( 'mobile-frontend-nearby-noresults-guidance' )\n\t\t},\n\t\thttp: {\n\t\t\theading: mw.msg( 'mobile-frontend-nearby-error' ),\n\t\t\thasHeading: true,\n\t\t\tmsg: mw.msg( 'mobile-frontend-nearby-error-guidance' )\n\t\t},\n\t\tincompatible: {\n\t\t\theading: mw.msg( 'mobile-frontend-nearby-requirements' ),\n\t\t\thasHeading: true,\n\t\t\tmsg: mw.msg( 'mobile-frontend-nearby-requirements-guidance' )\n\t\t}\n\t},\n\t/**\n\t * @memberof Nearby\n\t * @instance\n\t */\n\ttemplatePartials: util.extend( {}, WatchstarPageList.prototype.templatePartials, {\n\t\tpageList: WatchstarPageList.prototype.template,\n\t\tmessageBox: MessageBox.prototype.template\n\t} ),\n\t/**\n\t * @memberof Nearby\n\t * @instance\n\t */\n\ttemplate: mw.template.get( 'mobile.special.nearby.scripts', 'Nearby.hogan' ),\n\t/**\n\t * @memberof Nearby\n\t * @instance\n\t * @mixes WatchstarPageList#defaults\n\t * @property {Object} defaults Default options hash.\n\t * @property {mw.Api} defaults.api\n\t * @property {Object} defaults.errorOptions options to pass to a messagebox template\n\t * tells the user that their location is being looked up\n\t */\n\tdefaults: util.extend( {}, WatchstarPageList.prototype.defaults, {\n\t\terrorOptions: undefined\n\t} ),\n\t/**\n\t * Request pages from api based on provided options.\n\t * When options.longitude and options.latitude set getPages near that location.\n\t * If those are not present use options.title to find pages near that title.\n\t * If no valid options given resolve return object with error message.\n\t * @memberof Nearby\n\t * @instance\n\t * @param {Object} options Configuration options\n\t * @return {jQuery.Deferred}\n\t * @private\n\t */\n\t_find: function ( options ) {\n\t\tvar result = util.Deferred(),\n\t\t\tself = this;\n\n\t\t/**\n\t\t * Handler for successful query\n\t\t * @param {Array} pages as passed by then callback of Nearby##getPages\n\t\t */\n\t\tfunction pagesSuccess( pages ) {\n\t\t\toptions.pages = pages;\n\t\t\tif ( pages && pages.length === 0 ) {\n\t\t\t\toptions.errorOptions = self._errorOptions( 'empty' );\n\t\t\t}\n\t\t\tself._isLoading = false;\n\t\t\tresult.resolve( options );\n\t\t}\n\n\t\t/**\n\t\t * Handler for failed query\n\t\t *\n\t\t * @param {string} code Error Code\n\t\t */\n\t\tfunction pagesError( code ) {\n\t\t\tself._isLoading = false;\n\t\t\toptions.errorOptions = self._errorOptions( code );\n\t\t\tresult.resolve( options );\n\t\t}\n\n\t\tif ( options.latitude && options.longitude ) {\n\t\t\tthis.nearbyApi.getPages(\n\t\t\t\t{\n\t\t\t\t\tlatitude: options.latitude,\n\t\t\t\t\tlongitude: options.longitude\n\t\t\t\t},\n\t\t\t\tthis.range, options.exclude\n\t\t\t).then( pagesSuccess, pagesError );\n\t\t} else if ( options.pageTitle ) {\n\t\t\tthis.nearbyApi.getPagesAroundPage( options.pageTitle, this.range )\n\t\t\t\t.then( pagesSuccess, pagesError );\n\t\t} else {\n\t\t\tif ( options.errorType ) {\n\t\t\t\toptions.errorOptions = this._errorOptions( options.errorType );\n\t\t\t}\n\t\t\tresult.resolve( options );\n\t\t}\n\t\treturn result;\n\t},\n\t/**\n\t * Generate a list of options that can be passed to a messagebox template.\n\t * @memberof Nearby\n\t * @instance\n\t * @private\n\t * @param {string} key to a defined error message\n\t * @param {string} msg Message to use, instead of a mapped error message\n\t *  from this.errorMessages\n\t * @return {Object}\n\t */\n\t_errorOptions: function ( key ) {\n\t\tvar message = this.errorMessages[ key ] || this.errorMessages.http;\n\t\treturn util.extend( {\n\t\t\tclassName: 'errorbox'\n\t\t}, message );\n\t},\n\t/**\n\t * @inheritdoc\n\t * @memberof Nearby\n\t * @instance\n\t */\n\tpostRender: function () {\n\t\tvar self = this;\n\n\t\tif ( !this._isLoading ) {\n\t\t\tthis.$el.find( '.page-list' ).removeClass( 'hidden' );\n\t\t}\n\t\tWatchstarPageList.prototype.postRender.apply( this );\n\t\tthis._postRenderLinks();\n\t\t// FIXME: This should probably just be $( function () {} )\n\t\tthis.$el.find( function () {\n\t\t\t// todo: use the local emitter when refresh() doesn't recreate the\n\t\t\t//       OO.EventEmitter by calling the super's constructor.\n\t\t\tself.eventBus.emit( NEARBY_EVENT_POST_RENDER );\n\t\t} );\n\t},\n\t/**\n\t * Hijack links to apply several customisations to them:\n\t * Ensure that when clicked they register an uploads funnel.\n\t * Ensure that when a user navigates back to the page their page position is restored using\n\t * fragment identifier trickery.\n\t * @private\n\t * @memberof Nearby\n\t * @instance\n\t */\n\t_postRenderLinks: function () {\n\t\tvar self = this;\n\t\tthis.$el.find( 'a' ).each( function ( i ) {\n\t\t\t// FIXME: not unique if multiple Nearby objects on same page\n\t\t\tself.$el.find( this ).attr( 'id', 'nearby-page-list-item-' + i );\n\t\t} ).on( 'click', this.onItemClick );\n\t},\n\t/**\n\t * Refresh the list of the nearby articles depending on the options.\n\t * The current location, latitude/longitude, or page title can be used\n\t * to find the articles.\n\t * @memberof Nearby\n\t * @instance\n\t * @param {Object} options Configuration options\n\t * @throws {Error} If Nearby has not been initialised correctly.\n\t * @return {jQuery.Deferred}\n\t */\n\trefresh: function ( options ) {\n\t\tvar self = this,\n\t\t\t_super = WatchstarPageList;\n\n\t\tthis.$el.find( '.page-list' ).addClass( 'hidden' );\n\t\t// Run it once for loader etc\n\t\tthis._isLoading = true;\n\t\tif ( ( options.latitude && options.longitude ) || options.pageTitle ) {\n\t\t\t// Flush any existing list of pages\n\t\t\toptions.pages = [];\n\n\t\t\t// Get some new pages\n\t\t\treturn this._find( options ).then( function ( options ) {\n\t\t\t\t_super.call( self, options );\n\t\t\t}, function ( errorType ) {\n\t\t\t\toptions.errorOptions = self._errorOptions( errorType );\n\t\t\t\tself._isLoading = false;\n\t\t\t\t_super.call( self, options );\n\t\t\t} );\n\t\t} else {\n\t\t\tthrow new Error( 'No title or longitude, latitude options have been passed' );\n\t\t}\n\t}\n} );\n\nmodule.exports = Nearby;\n","var limit = 50,\n\tPage = require( '../mobile.startup/Page' ),\n\tns = mw.config.get( 'wgContentNamespaces' ),\n\tutil = require( '../mobile.startup/util' ),\n\textendSearchParams = require( '../mobile.startup/extendSearchParams' );\n\n/**\n * API for retrieving nearby pages\n * @class NearbyGateway\n * @param {Object} options Configuration options\n * @param {mw.Api} options.api\n */\nfunction NearbyGateway( options ) {\n\tthis.api = options.api;\n}\n\nNearbyGateway.prototype = {\n\t/**\n\t * Returns a human readable string stating the distance in meters or kilometers\n\t * depending on size.\n\t * @memberof NearbyGateway\n\t * @instance\n\t * @private\n\t * @param {number} d The distance in meters.\n\t * @return {string} message stating how far the user is from the point of interest.\n\t */\n\t_distanceMessage: function ( d ) {\n\t\tif ( d < 1 ) {\n\t\t\td *= 100;\n\t\t\td = Math.ceil( d ) * 10;\n\t\t\tif ( d === 1000 ) {\n\t\t\t\td = 1;\n\t\t\t} else {\n\t\t\t\treturn mw.msg( 'mobile-frontend-nearby-distance-meters', mw.language.convertNumber( d ) );\n\t\t\t}\n\t\t} else {\n\t\t\tif ( d > 2 ) {\n\t\t\t\td *= 10;\n\t\t\t\td = Math.ceil( d ) / 10;\n\t\t\t\td = d.toFixed( 1 );\n\t\t\t} else {\n\t\t\t\td *= 100;\n\t\t\t\td = Math.ceil( d ) / 100;\n\t\t\t\td = d.toFixed( 2 );\n\t\t\t}\n\t\t}\n\t\treturn mw.msg( 'mobile-frontend-nearby-distance', mw.language.convertNumber( d ) );\n\t},\n\t/**\n\t * Returns a list of pages around a given point\n\t * @memberof NearbyGateway\n\t * @instance\n\t * @param {Object} coords In form { latitude: 0, longitude: 2 }\n\t * @param {number} range Number of meters to perform a geosearch for\n\t * @param {string} exclude Name of a title to exclude from the list of results\n\t * @return {jQuery.Deferred} Object taking list of pages as argument\n\t */\n\tgetPages: function ( coords, range, exclude ) {\n\t\treturn this._search( {\n\t\t\tggscoord: [ coords.latitude, coords.longitude ]\n\t\t}, range, exclude );\n\t},\n\n\t/**\n\t * Gets the pages around a page. It excludes itself from the search\n\t * @memberof NearbyGateway\n\t * @instance\n\t * @param {string} page Page title like \"W_San_Francisco\"\n\t * @param {number} range Number of meters to perform a geosearch for\n\t * @return {jQuery.Deferred} Object taking list of pages as argument\n\t */\n\tgetPagesAroundPage: function ( page, range ) {\n\t\treturn this._search( {\n\t\t\tggspage: page\n\t\t}, range, page );\n\t},\n\n\t/**\n\t * Searches for pages nearby\n\t * @memberof NearbyGateway\n\t * @instance\n\t * @private\n\t * @param {Object} params Parameters to use for searching\n\t * @param {number} range Number of meters to perform a geosearch for\n\t * @param {string} exclude Name of a title to exclude from the list of results\n\t * @return {jQuery.Deferred} Object taking list of pages as argument\n\t */\n\t_search: function ( params, range, exclude ) {\n\t\tvar requestParams,\n\t\t\td = util.Deferred(),\n\t\t\tself = this;\n\n\t\trequestParams = extendSearchParams( 'nearby', {\n\t\t\tcolimit: 'max',\n\t\t\tprop: [ 'coordinates' ],\n\t\t\tgenerator: 'geosearch',\n\t\t\tggsradius: range,\n\t\t\tggsnamespace: ns,\n\t\t\tggslimit: limit\n\t\t}, params );\n\n\t\tif ( params.ggscoord ) {\n\t\t\trequestParams.codistancefrompoint = params.ggscoord;\n\t\t} else if ( params.ggspage ) {\n\t\t\trequestParams.codistancefrompage = params.ggspage;\n\t\t}\n\n\t\tthis.api.ajax( requestParams ).then( function ( resp ) {\n\t\t\tvar pages;\n\n\t\t\t// resp.query.pages is an Array<Page> instead of a map like in other\n\t\t\t// API requests\n\t\t\tif ( resp.query ) {\n\t\t\t\tpages = resp.query.pages || [];\n\t\t\t} else {\n\t\t\t\tpages = [];\n\t\t\t}\n\n\t\t\tpages = pages.map( function ( page, i ) {\n\t\t\t\tvar coords, p;\n\t\t\t\tp = Page.newFromJSON( page );\n\t\t\t\tp.anchor = 'item_' + i;\n\n\t\t\t\t// protect against declined bug T49133\n\t\t\t\tif ( page.coordinates ) {\n\t\t\t\t\tcoords = page.coordinates[0];\n\t\t\t\t\t// FIXME: Make part of the Page object\n\t\t\t\t\tp.dist = coords.dist / 1000;\n\t\t\t\t\tp.latitude = coords.lat;\n\t\t\t\t\tp.longitude = coords.lon;\n\t\t\t\t\tp.proximity = self._distanceMessage( p.dist );\n\t\t\t\t} else {\n\t\t\t\t\tp.dist = 0;\n\t\t\t\t}\n\t\t\t\tif ( exclude !== page.title ) {\n\t\t\t\t\treturn p;\n\t\t\t\t} else {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t} ).filter( function ( page ) { return !!page; } );\n\n\t\t\tpages.sort( function ( a, b ) {\n\t\t\t\treturn a.dist > b.dist ? 1 : -1;\n\t\t\t} );\n\t\t\td.resolve( pages );\n\t\t}, function ( error ) {\n\t\t\td.reject( error );\n\t\t} );\n\t\treturn d;\n\t}\n};\n\nmodule.exports = NearbyGateway;\n","var util = require( '../mobile.startup/util' );\n\n/**\n * API for retrieving gallery photos\n * @class PhotoListGateway\n *\n * @param {Object} options Configuration options\n * @param {mw.Api} options.api\n * @param {string} options.url for overriding default URI for API queries\n */\nfunction PhotoListGateway( options ) {\n\tthis.api = options.api;\n\tthis.url = options.url;\n\tthis.username = options.username;\n\tthis.category = options.category;\n\tthis.limit = 10;\n\tthis.continueParams = {\n\t\tcontinue: ''\n\t};\n\tthis.canContinue = true;\n}\n\n/**\n * Returns a description based on the file name using\n * a regular expression that strips the file type suffix,\n * namespace prefix and any\n * date suffix in format YYYY-MM-DD HH-MM\n * @memberof PhotoListGateway\n * @instance\n * @private\n * @param {string} title Title of file\n * @return {string} Description for file\n */\nfunction getDescription( title ) {\n\ttitle = title.replace( /\\.[^. ]+$/, '' ); // replace filename suffix\n\t// strip namespace: prefix and date suffix from remainder\n\treturn title.replace( /^[^:]*:/, '' )\n\t\t.replace( / \\d{4}-\\d{1,2}-\\d{1,2} \\d{1,2}-\\d{1,2}$/, '' );\n}\n\nPhotoListGateway.prototype = {\n\t/**\n\t * Returns the value in pixels of a medium thumbnail\n\t * @memberof PhotoListGateway\n\t * @instance\n\t * @return {number}\n\t */\n\tgetWidth: function () {\n\t\treturn mw.config.get( 'wgMFThumbnailSizes' ).small;\n\t},\n\t/**\n\t * Extracts image data from api response\n\t * @memberof PhotoListGateway\n\t * @instance\n\t * @private\n\t * @param {Object} page as returned by api request\n\t * @return {Object} describing image.\n\t */\n\t_getImageDataFromPage: function ( page ) {\n\t\tvar img = page.imageinfo[0];\n\t\treturn {\n\t\t\turl: img.thumburl,\n\t\t\ttitle: page.title,\n\t\t\ttimestamp: img.timestamp,\n\t\t\tdescription: getDescription( page.title ),\n\t\t\tdescriptionUrl: img.descriptionurl\n\t\t};\n\t},\n\t/**\n\t * Get the associated query needed to retrieve images from API based\n\t * on currently configured options.\n\t * @memberof PhotoListGateway\n\t * @instance\n\t * @return {Object}\n\t */\n\tgetQuery: function () {\n\t\tvar query = util.extend( {\n\t\t\taction: 'query',\n\t\t\tprop: 'imageinfo',\n\t\t\t// FIXME: [API] have to request timestamp since api returns an object\n\t\t\t// rather than an array thus we need a way to sort\n\t\t\tiiprop: 'url|timestamp',\n\t\t\tiiurlwidth: this.getWidth()\n\t\t}, this.continueParams );\n\n\t\tif ( this.username ) {\n\t\t\tutil.extend( query, {\n\t\t\t\tgenerator: 'allimages',\n\t\t\t\tgaiuser: this.username,\n\t\t\t\tgaisort: 'timestamp',\n\t\t\t\tgaidir: 'descending',\n\t\t\t\tgailimit: this.limit\n\t\t\t} );\n\t\t} else if ( this.category ) {\n\t\t\tutil.extend( query, {\n\t\t\t\tgenerator: 'categorymembers',\n\t\t\t\tgcmtitle: 'Category:' + this.category,\n\t\t\t\tgcmtype: 'file',\n\t\t\t\t// FIXME [API] a lot of duplication follows due to the silly way generators work\n\t\t\t\tgcmdir: 'descending',\n\t\t\t\tgcmlimit: this.limit\n\t\t\t} );\n\t\t}\n\n\t\tif ( this.url ) {\n\t\t\t// A foreign api is being accessed! Enable anonymous CORS queries!\n\t\t\tquery.origin = '*';\n\t\t}\n\t\treturn query;\n\t},\n\t/**\n\t * Request photos beginning with the current value of endTimestamp\n\t * @memberof PhotoListGateway\n\t * @instance\n\t * @return {jQuery.Deferred} where parameter is a list of JavaScript\n\t *  objects describing an image.\n\t */\n\tgetPhotos: function () {\n\t\tvar self = this;\n\n\t\treturn this.api.ajax( this.getQuery(), { url: this.url } ).then( function ( resp ) {\n\t\t\tvar photos = [];\n\t\t\tif ( resp.query && resp.query.pages ) {\n\t\t\t\t// FIXME: [API] in an ideal world imageData would be a sorted array\n\t\t\t\t// but it is a map of {[id]: page}\n\t\t\t\tphotos = Object.keys( resp.query.pages ).map( function ( id ) {\n\t\t\t\t\treturn self._getImageDataFromPage( resp.query.pages[id] );\n\t\t\t\t} ).sort( function ( a, b ) {\n\t\t\t\t\treturn a.timestamp < b.timestamp ? 1 : -1;\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\tif ( resp.continue !== undefined ) {\n\t\t\t\tself.continueParams = resp.continue;\n\t\t\t} else {\n\t\t\t\tself.canContinue = false;\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tcanContinue: self.canContinue,\n\t\t\t\t// FIXME: Should reply with a list of PhotoItem or Photo classes.\n\t\t\t\tphotos: photos\n\t\t\t};\n\t\t} );\n\t}\n};\n\nPhotoListGateway.test = {\n\tgetDescription: getDescription\n};\n\nmodule.exports = PhotoListGateway;\n","var\n\tmfExtend = require( '../mobile.startup/mfExtend' ),\n\tPageList = require( '../mobile.startup/PageList' ),\n\tWatchstarPageList = require( '../mobile.startup/watchstar/WatchstarPageList' ),\n\tScrollEndEventEmitter = require( '../mobile.startup/ScrollEndEventEmitter' ),\n\tutil = require( '../mobile.startup/util' ),\n\tWatchListGateway = require( './WatchListGateway' );\n\n/**\n * An extension of the WatchstarPageList which preloads pages as all being\n * watched.\n * @extends WatchstarPageList\n * @class WatchList\n * @uses ScrollEndEventEmitter\n *\n * @fires watched\n * @fires watch\n * @param {Object} params Configuration options\n * @param {OO.EventEmitter} params.eventBus Object used to listen for scroll:throttled events\n */\nfunction WatchList( params ) {\n\tvar lastTitle,\n\t\toptions = util.extend( {}, {\n\t\t\tisBorderBox: false\n\t\t}, params );\n\n\t// Set up infinite scroll helper and listen to events\n\tthis.scrollEndEventEmitter = new ScrollEndEventEmitter( options.eventBus );\n\tthis.scrollEndEventEmitter.on( ScrollEndEventEmitter.EVENT_SCROLL_END,\n\t\tthis._loadPages.bind( this ) );\n\n\tif ( options.el ) {\n\t\tlastTitle = this.getLastTitle( options.el );\n\t}\n\tthis.gateway = new WatchListGateway( options.api, lastTitle );\n\n\tWatchstarPageList.call( this, options );\n}\n\nmfExtend( WatchList, WatchstarPageList, {\n\t/**\n\t * @inheritdoc\n\t * @memberof WatchList\n\t * @instance\n\t */\n\tpreRender: function () {\n\t\t// The DOM will be modified. Prevent any false scroll end events from\n\t\t// being emitted.\n\t\tthis.scrollEndEventEmitter.disable();\n\t\tthis.scrollEndEventEmitter.setElement( this.$el );\n\t},\n\t/**\n\t * Also sets a watch uploads funnel.\n\t * @inheritdoc\n\t * @memberof WatchList\n\t * @instance\n\t */\n\tpostRender: function () {\n\t\tvar\n\t\t\t$items,\n\t\t\tstatuses;\n\n\t\t// Skip a level from WatchstarPageList directly to PageList.\n\t\tPageList.prototype.postRender.apply( this );\n\n\t\t$items = this.queryUnitializedItems();\n\n\t\t// WatchList requests list of watched pages. The list contains only\n\t\t// watched pages so it's safe to transform the title map to a status map\n\t\t// with each entry marked watched (true).\n\t\tstatuses = Object.keys( this.parsePagesFromItems( $items ) )\n\t\t\t.reduce( function ( statuses, title ) {\n\t\t\t\tstatuses[ title ] = true;\n\t\t\t\treturn statuses;\n\t\t\t}, {} );\n\t\tthis.renderItems( $items, statuses );\n\n\t\t// The list has been extended. Re-enable scroll end events.\n\t\tthis.scrollEndEventEmitter.enable();\n\t},\n\n\t/**\n\t * Loads pages from the api and triggers render.\n\t * Infinite scroll is re-enabled in postRender.\n\t * @memberof WatchList\n\t * @instance\n\t */\n\t_loadPages: function () {\n\t\tthis.gateway.loadWatchlist().then( function ( pages ) {\n\t\t\tpages.forEach( function ( page ) {\n\t\t\t\tthis.appendPage( page );\n\t\t\t}.bind( this ) );\n\t\t\tthis.render();\n\t\t}.bind( this ) );\n\t},\n\n\t/**\n\t * Appends a list item\n\t * @memberof WatchList\n\t * @instance\n\t * @param {Page} page\n\t */\n\tappendPage: function ( page ) {\n\t\t// wikidata descriptions should not show in this view.\n\t\tvar templateOptions = util.extend( {}, page.options, {\n\t\t\twikidataDescription: undefined\n\t\t} );\n\t\tthis.$el.append( this.templatePartials.item.render( templateOptions ) );\n\t},\n\n\t/**\n\t * Get the last title from the rendered HTML.\n\t * Used for initializing the API\n\t * @memberof WatchList\n\t * @instance\n\t * @param {jQuery.Object} $el Dom element of the list\n\t * @return {string}\n\t */\n\tgetLastTitle: function ( $el ) {\n\t\treturn $el.find( 'li:last' ).attr( 'title' );\n\t}\n} );\n\nmodule.exports = WatchList;\n","var Page = require( '../mobile.startup/Page' ),\n\tutil = require( '../mobile.startup/util' ),\n\textendSearchParams = require( '../mobile.startup/extendSearchParams' );\n\n/**\n * @class WatchListGateway\n * @param {mw.Api} api\n * @param {string} lastTitle of page listed in Watchlist to be used as a continuation parameter\n */\nfunction WatchListGateway( api, lastTitle ) {\n\tthis.api = api;\n\t// Try to keep it in sync with SpecialMobileWatchlist::LIMIT (php)\n\tthis.limit = 50;\n\n\tif ( lastTitle ) {\n\t\tthis.continueParams = {\n\t\t\tcontinue: 'gwrcontinue||',\n\t\t\tgwrcontinue: '0|' + lastTitle.replace( / /g, '_' )\n\t\t};\n\t\tthis.shouldSkipFirstTitle = true;\n\t} else {\n\t\tthis.continueParams = {\n\t\t\tcontinue: ''\n\t\t};\n\t\tthis.shouldSkipFirstTitle = false;\n\t}\n\n\tthis.canContinue = true;\n}\n\nWatchListGateway.prototype = {\n\t/**\n\t * Load the list of items on the watchlist\n\t * @return {jQuery.Deferred}\n\t */\n\tloadWatchlist: function () {\n\t\tvar self = this,\n\t\t\tparams = extendSearchParams( 'watchlist', {\n\t\t\t\tprop: [ 'info', 'revisions' ],\n\t\t\t\trvprop: 'timestamp|user',\n\t\t\t\tgenerator: 'watchlistraw',\n\t\t\t\tgwrnamespace: '0',\n\t\t\t\tgwrlimit: this.limit\n\t\t\t}, this.continueParams );\n\n\t\tif ( this.canContinue === false ) {\n\t\t\treturn util.Deferred().resolve( [] );\n\t\t}\n\t\treturn this.api.get( params, {\n\t\t\turl: this.apiUrl\n\t\t} ).then( function ( data ) {\n\t\t\tif ( data.continue !== undefined ) {\n\t\t\t\tself.continueParams = data.continue;\n\t\t\t} else {\n\t\t\t\tself.canContinue = false;\n\t\t\t}\n\n\t\t\treturn self.parseData( data );\n\t\t} );\n\t},\n\n\t/**\n\t * Parse api response data into pagelist item format\n\t * @param {Object[]} data\n\t * @return {Page[]}\n\t */\n\tparseData: function ( data ) {\n\t\tvar pages;\n\n\t\tif ( !data.query || !data.query.pages ) {\n\t\t\treturn [];\n\t\t}\n\n\t\tpages = data.query.pages;\n\n\t\t// Sort results alphabetically (the api map doesn't have any order). The\n\t\t// watchlist is ordered alphabetically right now.\n\t\tpages.sort( function ( p1, p2 ) {\n\t\t\treturn p1.title === p2.title ? 0 : ( p1.title < p2.title ? -1 : 1 );\n\t\t} );\n\n\t\t// If we requested from the last item of the previous page, we shall\n\t\t// remove the first result (to avoid it being repeated)\n\t\tif ( this.shouldSkipFirstTitle ) {\n\t\t\tpages = pages.slice( 1 );\n\t\t\tthis.shouldSkipFirstTitle = false;\n\t\t}\n\n\t\t// Transform the items to a sensible format\n\t\treturn pages.map( Page.newFromJSON );\n\t}\n\n};\n\nmodule.exports = WatchListGateway;\n","var\n\tView = require( './View' ),\n\tmfExtend = require( './mfExtend' );\n\n/**\n * A wrapper for creating an anchor.\n * @class Anchor\n * @extends View\n */\nfunction Anchor() {\n\tView.apply( this, arguments );\n}\n\nmfExtend( Anchor, View, {\n\t/**\n\t * @inheritdoc\n\t * @memberof Anchor\n\t * @instance\n\t */\n\tisTemplateMode: true,\n\t/**\n\t * @memberof Anchor\n\t * @instance\n\t * @mixes View#defaults\n\t * @property {Object} defaults Default options hash.\n\t * @property {boolean} defaults.progressive is progressive action\n\t * @property {boolean} defaults.destructive is destructive action\n\t * @property {string} defaults.additionalClassNames Additional class name(s).\n\t * @property {string} defaults.href url\n\t * @property {string} defaults.label of anchor\n\t */\n\tdefaults: {\n\t\tprogressive: undefined,\n\t\tdestructive: undefined,\n\t\tadditionalClassNames: '',\n\t\thref: undefined,\n\t\tlabel: undefined\n\t},\n\t/**\n\t * @inheritdoc\n\t * @memberof Anchor\n\t * @instance\n\t */\n\ttemplate: mw.template.get( 'mobile.startup', 'anchor.hogan' )\n} );\n\nmodule.exports = Anchor;\n","var\n\tutil = require( './util' ),\n\tbrowser;\n\n/**\n * Memoize a class method. Caches the result of the method based on the\n * arguments. Instances do not share a cache.\n * @param {Function} method Method to be memoized\n * @return {Function}\n */\nfunction memoize( method ) {\n\t/**\n\t * Memoized version of the method\n\t * @return {Function}\n\t */\n\tvar memoized = function () {\n\t\tvar cache = this[ '__cache' + memoized.cacheId ] ||\n\t\t\t( this[ '__cache' + memoized.cacheId ] = {} ),\n\t\t\tkey = [].join.call( arguments, '|' );\n\t\tif ( Object.prototype.hasOwnProperty.call( cache, key ) ) {\n\t\t\treturn cache[ key ];\n\t\t}\n\t\treturn ( cache[ key ] = method.apply( this, arguments ) );\n\t};\n\tmemoized.cacheId = Date.now().toString() + Math.random().toString();\n\treturn memoized;\n}\n\n/**\n * Representation of user's current browser\n * @class Browser\n * @param {string} ua the user agent of the current browser\n * @param {jQuery.Object} $container an element to associate with the Browser object\n */\nfunction Browser( ua, $container ) {\n\tthis.userAgent = ua;\n\tthis.$el = $container;\n}\n\nBrowser.prototype = {\n\t/**\n\t * Returns whether the current browser is an ios device.\n\t * FIXME: jquery.client does not support iPad detection so we cannot use it.\n\t * @memberof Browser\n\t * @instance\n\t * @param {number} [version] integer describing a specific version you want to test against.\n\t * @return {boolean}\n\t */\n\tisIos: memoize( function ( version ) {\n\t\tvar ua = this.userAgent,\n\t\t\tios = /ipad|iphone|ipod/i.test( ua );\n\n\t\tif ( ios && version ) {\n\t\t\tswitch ( version ) {\n\t\t\t\tcase 8:\n\t\t\t\t\t// Test UA for iOS8. Or for simulator look for Version 8\n\t\t\t\t\t// In the iOS simulator the OS is the host machine OS version\n\t\t\t\t\t// This makes testing in iOS8 simulator work as expected\n\t\t\t\t\treturn /OS 8_/.test( ua ) || /Version\\/8/.test( ua );\n\t\t\t\tcase 4:\n\t\t\t\t\treturn /OS 4_/.test( ua );\n\t\t\t\tcase 5:\n\t\t\t\t\treturn /OS 5_/.test( ua );\n\t\t\t\tdefault:\n\t\t\t\t\treturn false;\n\t\t\t}\n\t\t} else {\n\t\t\treturn ios;\n\t\t}\n\t} ),\n\t/**\n\t * Determine if a device has a widescreen.\n\t * @memberof Browser\n\t * @instance\n\t * @return {boolean}\n\t */\n\tisWideScreen: memoize( function () {\n\t\tvar val = parseInt( mw.config.get( 'wgMFDeviceWidthTablet' ), 10 );\n\t\t// Check portrait and landscape mode to be consistent\n\t\treturn window.innerWidth >= val || window.innerHeight >= val;\n\t} ),\n\t/**\n\t * Checks browser support for CSS transforms, transitions\n\t * and CSS animation.\n\t * Currently assumes support for the latter 2 in the case of the\n\t * former.\n\t * See http://stackoverflow.com/a/12621264/365238\n\t * @memberof Browser\n\t * @instance\n\t * @return {boolean}\n\t */\n\tsupportsAnimations: memoize( function () {\n\t\tvar elemStyle = document.createElement( 'foo' ).style;\n\t\tfunction supportsProperty( property ) {\n\t\t\t// We only test \"webkit-\", because that's the only prefix needed for the relevant\n\t\t\t// properties (in supportsAnimations) and supported browsers. If usage is expanded,\n\t\t\t// other prefixes may need to be checked as well.\n\t\t\treturn property in elemStyle ||\n\t\t\t\t( 'webkit' + property[ 0 ].toUpperCase() + property.slice( 1 ) ) in elemStyle;\n\t\t}\n\t\treturn supportsProperty( 'animationName' ) &&\n\t\t\tsupportsProperty( 'transform' ) &&\n\t\t\tsupportsProperty( 'transition' );\n\t} ),\n\t/**\n\t * Whether touchstart and other touch events are supported by the current browser.\n\t * @memberof Browser\n\t * @instance\n\t * @return {boolean}\n\t */\n\tsupportsTouchEvents: memoize( function () {\n\t\treturn 'ontouchstart' in window;\n\t} ),\n\t/**\n\t * Detect if browser supports geolocation\n\t * @memberof Browser\n\t * @instance\n\t * @return {boolean}\n\t */\n\tsupportsGeoLocation: memoize( function () {\n\t\treturn 'geolocation' in window.navigator;\n\t} )\n};\n\n/**\n * @memberof Browser\n * @return {Browser}\n */\nBrowser.getSingleton = function () {\n\tvar $html;\n\tif ( !browser ) {\n\t\t$html = util.getDocument();\n\t\tbrowser = new Browser( window.navigator.userAgent, $html );\n\t}\n\treturn browser;\n};\n\nmodule.exports = Browser;\n","var\n\tmfExtend = require( './mfExtend' ),\n\tView = require( './View' );\n\n/**\n * A wrapper for creating a button.\n * @class Button\n * @extends View\n *\n * @param {Object} options Configuration options\n */\nfunction Button( options ) {\n\tif ( options.href ) {\n\t\toptions.tagName = 'a';\n\t}\n\tView.call( this, options );\n}\n\nmfExtend( Button, View, {\n\t/**\n\t * @inheritdoc\n\t * @memberof Button\n\t * @instance\n\t */\n\tisTemplateMode: true,\n\t/**\n\t * @memberof Button\n\t * @instance\n\t * @mixes View#defaults\n\t * @property {Object} defaults Default options hash.\n\t * @property {string} defaults.tagName The name of the tag in which the button is wrapped.\n\t * @property {boolean} defaults.block is stacked button\n\t * @property {boolean} defaults.progressive is progressive action\n\t *   This option is deprecated. Please use `progressive`.\n\t * @property {boolean} defaults.quiet is quiet button\n\t * @property {boolean} defaults.destructive is destructive action\n\t * @property {string} defaults.additionalClassNames Additional class name(s).\n\t * @property {string} defaults.href url\n\t * @property {string} defaults.label of button\n\t */\n\tdefaults: {\n\t\ttagName: 'a',\n\t\tblock: undefined,\n\t\tprogressive: undefined,\n\t\tdestructive: undefined,\n\t\tquiet: undefined,\n\t\tadditionalClassNames: '',\n\t\thref: undefined,\n\t\tlabel: undefined\n\t},\n\t/**\n\t * @memberof Button\n\t * @instance\n\t */\n\ttemplate: mw.template.get( 'mobile.startup', 'button.hogan' )\n} );\n\nmodule.exports = Button;\n","var\n\tmfExtend = require( './mfExtend' ),\n\tDrawer = require( './Drawer' ),\n\tutil = require( './util' ),\n\tButton = require( './Button' ),\n\tAnchor = require( './Anchor' );\n\n/**\n * @typedef {string|number|boolean|undefined} QueryVal\n * @typedef {Object.<string, QueryVal|QueryVal[]>} QueryParams\n *\n * @typedef {Object} Options\n * @prop {string} [returnTo]\n * @prop {QueryParams} [queryParams]\n * @prop {QueryParams} [signupQueryParams]\n * @prop {Object} [options.progressiveButton] template options for Button element for signing in\n * @prop {Object} [options.actionAnchor] template options for Anchor element for signing up\n */\n\n/**\n * This creates the drawer at the bottom of the screen that appears when an anonymous\n * user tries to perform an action that requires being logged in. It presents the user\n * with options to log in or sign up for a new account.\n * @class CtaDrawer\n * @extends Drawer\n * @uses Button\n * @uses Icon\n * @uses Anchor\n * @param {Options} options\n */\nfunction CtaDrawer( options ) {\n\tDrawer.call( this,\n\t\tutil.extend( {}, Drawer.prototype.defaults, {\n\t\t\tprogressiveButton: new Button( {\n\t\t\t\tprogressive: true,\n\t\t\t\tlabel: mw.msg( 'mobile-frontend-watchlist-cta-button-login' )\n\t\t\t} ).options,\n\t\t\tactionAnchor: new Anchor( {\n\t\t\t\tprogressive: true,\n\t\t\t\tlabel: mw.msg( 'mobile-frontend-watchlist-cta-button-signup' )\n\t\t\t} ).options\n\t\t}, options )\n\t);\n}\n\nmfExtend( CtaDrawer, Drawer, {\n\t/**\n\t * @memberof CtaDrawer\n\t * @instance\n\t */\n\ttemplatePartials: util.extend( {}, Drawer.prototype.templatePartials, {\n\t\tbutton: Button.prototype.template,\n\t\tanchor: Anchor.prototype.template\n\t} ),\n\t/**\n\t\t * @memberof CtaDrawer\n\t\t * @instance\n\t\t */\n\ttemplate: mw.template.get( 'mobile.startup', 'CtaDrawer.hogan' ),\n\t/**\n\t\t * @inheritdoc\n\t\t * @memberof CtaDrawer\n\t\t * @instance\n\t\t */\n\tpreRender: function () {\n\t\tvar params = redirectParams( this.options.queryParams, this.options.returnTo );\n\n\t\t// Give the button and the anchor a default target, if it isn't set already. Buttons are\n\t\t// customized by Minerva's red link drawer, skins.minerva.scripts/init.js.\n\t\tif ( !this.options.progressiveButton.href ) {\n\t\t\tthis.options.progressiveButton.href = mw.util.getUrl( 'Special:UserLogin', params );\n\t\t}\n\t\tif ( !this.options.actionAnchor.href ) {\n\t\t\tthis.options.actionAnchor.href = mw.util.getUrl(\n\t\t\t\t'Special:UserLogin', signUpParams( params, this.options.signupQueryParams )\n\t\t\t);\n\t\t}\n\t}\n} );\n\n/**\n * Special:UserLogin post-request redirect query parameters.\n * @param {QueryParams} params\n * @param {string} [redirectURL]\n * @return {QueryParams}\n */\nfunction redirectParams( params, redirectURL ) {\n\treturn util.extend( {\n\t\t// use wgPageName as this includes the namespace if outside Main\n\t\treturnto: redirectURL || mw.config.get( 'wgPageName' )\n\t}, params );\n}\n\n/**\n * Special:UserLogin account creation query parameters.\n * @param {...QueryParams} params\n * @return {QueryParams}\n */\nfunction signUpParams() {\n\t[].push.call( arguments, { type: 'signup' } );\n\treturn util.extend.apply( util, arguments );\n}\n\nCtaDrawer.prototype.test = {\n\tredirectParams: redirectParams,\n\tsignUpParams: signUpParams\n};\n\nmodule.exports = CtaDrawer;\n","var\n\tmfExtend = require( './mfExtend' ),\n\tPanel = require( './Panel' ),\n\tutil = require( './util' ),\n\tIcon = require( './Icon' );\n\n/**\n * A {@link View} that pops up from the bottom of the screen.\n * @class Drawer\n * @extends Panel\n * @param {Object} [props]\n */\nfunction Drawer( props ) {\n\tPanel.call( this,\n\t\tutil.extend(\n\t\t\t{ className: 'drawer position-fixed' },\n\t\t\tprops,\n\t\t\t{ events: util.extend( { click: 'stopPropagation' }, ( props || {} ).events ) }\n\t\t)\n\t);\n}\n\nmfExtend( Drawer, Panel, {\n\t/**\n\t * @memberof Drawer\n\t * @instance\n\t * @mixes Panel#defaults\n\t * @property {Object} defaults Default options hash.\n\t * @property {string} defaults.cancelButton HTML of the button that closes the drawer.\n\t */\n\tdefaults: util.extend( {}, Panel.prototype.defaults, {\n\t\t// Used by CtaDrawer, BlockMessage.\n\t\tcollapseIcon: new Icon( {\n\t\t\tname: 'arrow',\n\t\t\tadditionalClassNames: 'cancel'\n\t\t} ).options\n\t} ),\n\t/**\n\t * @memberof Drawer\n\t * @instance\n\t */\n\ttemplatePartials: util.extend( {}, Panel.prototype.templatePartials, {\n\t\ticon: Icon.prototype.template\n\t} ),\n\t/**\n\t * Defines an element that the Drawer should automatically be appended to.\n\t * @memberof Drawer\n\t * @instance\n\t * @property {string}\n\t */\n\tappendToElement: 'body',\n\t/**\n\t * Whether the drawer should disappear on a scroll event\n\t * @memberof Drawer\n\t * @instance\n\t * @property {boolean}\n\t */\n\tcloseOnScroll: true,\n\n\t/**\n\t * @inheritdoc\n\t * @memberof Drawer\n\t * @instance\n\t */\n\tpostRender: function () {\n\t\tvar self = this;\n\t\t// This module might be loaded at the top of the page e.g. Special:Uploads\n\t\t// Thus ensure we wait for the DOM to be loaded\n\t\tutil.docReady( function () {\n\t\t\tself.appendTo( self.appendToElement );\n\t\t\tself.$el.parent().addClass( 'has-drawer' );\n\t\t} );\n\t\tthis.on( 'show', this.onShowDrawer.bind( this ) );\n\t\tthis.on( 'hide', this.onHideDrawer.bind( this ) );\n\t},\n\t/**\n\t * Stop Propagation event handler\n\t * @memberof Drawer\n\t * @instance\n\t * @param {Object} ev event object\n\t * Allow the drawer itself to be clickable (e.g. for copying and pasting references\n\t * clicking links in reference)\n\t */\n\tstopPropagation: function ( ev ) {\n\t\tev.stopPropagation();\n\t},\n\n\t/**\n\t * ShowDrawer event handler\n\t * @memberof Drawer\n\t * @instance\n\t */\n\tonShowDrawer: function () {\n\t\tvar self = this;\n\n\t\tthis.$el.parent().addClass( 'drawer-visible' );\n\n\t\tsetTimeout( function () {\n\t\t\tvar $window = util.getWindow();\n\t\t\t$window.one( 'click.drawer', self.hide.bind( self ) );\n\t\t\tif ( self.closeOnScroll ) {\n\t\t\t\t$window.one( 'scroll.drawer', self.hide.bind( self ) );\n\t\t\t}\n\t\t}, self.minHideDelay );\n\t},\n\n\t/**\n\t * HideDrawer event handler\n\t * @memberof Drawer\n\t * @instance\n\t */\n\tonHideDrawer: function () {\n\t\tthis.$el.parent().removeClass( 'drawer-visible' );\n\t\t// .one() registers one callback for scroll and click independently\n\t\t// if one fired, get rid of the other one\n\t\tutil.getWindow().off( '.drawer' );\n\t}\n} );\n\nmodule.exports = Drawer;\n","var\n\tmfExtend = require( './mfExtend' ),\n\tView = require( './View' );\n\n/**\n * A wrapper for creating an icon.\n * @class Icon\n * @extends View\n *\n * @param {Object} options Configuration options\n */\nfunction Icon( options ) {\n\tif ( options.hasText ) {\n\t\toptions.modifier = 'mw-ui-icon-before';\n\t}\n\tif ( options.href ) {\n\t\toptions.tagName = 'a';\n\t}\n\tView.call( this, options );\n}\n\nmfExtend( Icon, View, {\n\t/**\n\t * @inheritdoc\n\t * @memberof Icon\n\t * @instance\n\t */\n\tpreRender: function () {\n\t\tthis.setRotationClass();\n\t},\n\t/**\n\t * Internal method that sets the correct rotation class for the icon\n\t * based on the value of rotation\n\t * @memberof Icon\n\t * @instance\n\t * @private\n\t */\n\tsetRotationClass: function () {\n\t\tvar options = this.options;\n\t\tif ( options.rotation ) {\n\t\t\tswitch ( options.rotation ) {\n\t\t\t\tcase -180:\n\t\t\t\tcase 180:\n\t\t\t\t\toptions._rotationClass = 'mf-mw-ui-icon-rotate-flip';\n\t\t\t\t\tbreak;\n\t\t\t\tcase -90:\n\t\t\t\t\toptions._rotationClass = 'mf-mw-ui-icon-rotate-anti-clockwise';\n\t\t\t\t\tbreak;\n\t\t\t\tcase 90:\n\t\t\t\t\toptions._rotationClass = 'mf-mw-ui-icon-rotate-clockwise';\n\t\t\t\t\tbreak;\n\t\t\t\tcase 0:\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new Error( 'Bad value for rotation given. Must be ±90, 0 or ±180.' );\n\t\t\t}\n\t\t}\n\t},\n\t/**\n\t * @inheritdoc\n\t * @memberof Icon\n\t * @instance\n\t */\n\tisTemplateMode: true,\n\t/**\n\t * @memberof Icon\n\t * @instance\n\t * @mixes View#defaults\n\t * @property {Object} defaults Default options hash.\n\t * @property {boolean} defaults.hasText Whether the icon has text.\n\t * @property {boolean} defaults.isSmall Whether the icon should be small.\n\t * @property {string} [defaults.href] value of href attribute,\n\t *  when set tagName will default to anchor tag\n\t * @property {string} defaults.tagName The name of the tag in which the icon is wrapped.\n\t *  Defaults to 'a' when href option present.\n\t * @property {string} defaults.base String used as a base for generating class names.\n\t * Defaults to 'mw-ui-icon'.\n\t * @property {string} defaults.name Name of the icon.\n\t * @property {string} defaults.modifier Additional class name.\n\t * Defaults to 'mw-ui-icon-element'.\n\t * @property {string} defaults.title Tooltip text.\n\t * @property {boolean} defaults.rotation will rotate the icon by a certain number\n\t *  of degrees.\n\t *  Must be ±90, 0 or ±180 or will throw exception.\n\t */\n\tdefaults: {\n\t\trotation: 0,\n\t\thasText: false,\n\t\thref: undefined,\n\t\tglyphPrefix: 'mf',\n\t\ttagName: 'div',\n\t\tisSmall: false,\n\t\tbase: 'mw-ui-icon',\n\t\tname: '',\n\t\tmodifier: 'mw-ui-icon-element',\n\t\ttitle: ''\n\t},\n\t/**\n\t * Return the full class name that is required for the icon to render\n\t * @memberof Icon\n\t * @instance\n\t * @return {string}\n\t */\n\tgetClassName: function () {\n\t\treturn this.$el.attr( 'class' );\n\t},\n\t/**\n\t * Return the class that relates to the icon glyph\n\t * @memberof Icon\n\t * @instance\n\t * @return {string}\n\t */\n\tgetGlyphClassName: function () {\n\t\treturn this.options.base + '-' + this.options.glyphPrefix + '-' + this.options.name;\n\t},\n\t/**\n\t * Return the HTML representation of this view\n\t * @memberof Icon\n\t * @instance\n\t * @return {string}\n\t */\n\ttoHtmlString: function () {\n\t\treturn this.parseHTML( '<div>' ).append( this.$el ).html();\n\t},\n\ttemplate: mw.template.get( 'mobile.startup', 'icon.hogan' )\n} );\n\nmodule.exports = Icon;\n","var\n\tView = require( './View' ),\n\tmfExtend = require( './mfExtend' );\n\n/**\n * @class MessageBox\n * @extends View\n */\nfunction MessageBox() {\n\tView.apply( this, arguments );\n}\n\nmfExtend( MessageBox, View, {\n\t/**\n\t * @inheritdoc\n\t * @memberof MessageBox\n\t * @instance\n\t */\n\tisTemplateMode: true,\n\t/**\n\t * @memberof MessageBox\n\t * @instance\n\t * @mixes 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.className either errorbox, warningbox or successbox\n\t */\n\tdefaults: {},\n\t/**\n\t * @memberof MessageBox\n\t * @instance\n\t */\n\ttemplate: mw.template.get( 'mobile.startup', 'MessageBox.hogan' )\n} );\n\nmodule.exports = MessageBox;\n","var\n\tView = require( './View' ),\n\tIcon = require( './Icon' ),\n\tButton = require( './Button' ),\n\tAnchor = require( './Anchor' ),\n\ticons = require( './icons' ),\n\tutil = require( './util' ),\n\tbrowser = require( './Browser' ).getSingleton(),\n\tmfExtend = require( './mfExtend' );\n\n/**\n * Mobile modal window\n * @typedef {Object} HeaderButtonDefinition\n * @property {string} href of button\n * @property {string} className of button\n * @property {boolean} disabled whether button is disabled initially\n * @property {string} msg button label\n * @class Overlay\n * @extends View\n * @uses Icon\n * @uses Button\n * @fires Overlay#Overlay-exit\n * @fires Overlay#hide\n * @param {Object} props\n * @param {Object} props.events - custom events to be bound to the overlay.\n * @param {View[]} props.headerActions children (usually buttons or icons)\n *   that should be placed in the header actions\n * @param {boolean} props.noHeader renders an overlay without a header\n * @param {Function} props.onBeforeExit allows a consumer to prevent exits in certain\n *  situations. This callback gets the following parameters:\n *  - 1) the exit function which should be run after the consumer has made their changes.\n * @param {HeaderButtonDefinition[]} [props.headerButtons] define buttons to go in header\n */\nfunction Overlay( props ) {\n\tthis.isIos = browser.isIos();\n\t// Set to true when overlay has failed to load\n\tthis.hasLoadError = false;\n\n\tView.call(\n\t\tthis,\n\t\tutil.extend(\n\t\t\ttrue,\n\t\t\t{ className: 'overlay' },\n\t\t\tprops,\n\t\t\t{\n\t\t\t\tevents: util.extend(\n\t\t\t\t\t{\n\t\t\t\t\t\t// FIXME: Remove .initial-header selector\n\t\t\t\t\t\t'click .cancel, .confirm, .initial-header .back': 'onExitClick',\n\t\t\t\t\t\tclick: 'stopPropagation'\n\t\t\t\t\t},\n\t\t\t\t\tprops.events\n\t\t\t\t)\n\t\t\t}\n\t\t)\n\t);\n}\n\nmfExtend( Overlay, View, {\n\t/**\n\t * Is overlay fullscreen\n\t * @memberof Overlay\n\t * @instance\n\t * @property {boolean}\n\t */\n\tfullScreen: true,\n\n\t/**\n\t * True if this.hide() should be invoked before firing the Overlay-exit\n\t * event\n\t * @memberof Overlay\n\t * @instance\n\t * @property {boolean}\n\t */\n\thideOnExitClick: true,\n\n\ttemplatePartials: {\n\t\theader: mw.template.get( 'mobile.startup', 'header.hogan' ),\n\t\tanchor: Anchor.prototype.template,\n\t\tbutton: Button.prototype.template\n\t},\n\ttemplate: mw.template.get( 'mobile.startup', 'Overlay.hogan' ),\n\t/**\n\t * @memberof Overlay\n\t * @instance\n\t * @mixes View#defaults\n\t * @property {Object} defaults Default options hash.\n\t * @property {string} defaults.saveMessage Caption for save button on edit form.\n\t * @property {string} defaults.cancelButton HTML of the cancel button.\n\t * @property {string} defaults.backButton HTML of the back button.\n\t * @property {View[]} defaults.headerActions children (usually buttons or icons)\n\t *  that should be placed in the header actions\n\t * @property {HeaderButtonDefinition[]} defaults.headerButtons definitions\n\t * @property {boolean} defaults.headerChrome Whether the header has chrome.\n\t * @property {string} defaults.spinner HTML of the spinner icon.\n\t * @property {Object} [defaults.footerAnchor] options for an optional Anchor\n\t *  that can appear in the footer\n\t */\n\tdefaults: {\n\t\theaderActions: [],\n\t\tsaveMsg: mw.config.get( 'wgEditSubmitButtonLabelPublish' ) ?\n\t\t\tmw.msg( 'mobile-frontend-editor-publish' ) : mw.msg( 'mobile-frontend-editor-save' ),\n\t\tcancelButton: icons.cancel().toHtmlString(),\n\t\tbackButton: new Icon( {\n\t\t\ttagName: 'button',\n\t\t\tname: 'back',\n\t\t\tadditionalClassNames: 'back',\n\t\t\tlabel: mw.msg( 'mobile-frontend-overlay-close' )\n\t\t} ).toHtmlString(),\n\t\theaderChrome: false,\n\t\tspinner: icons.spinner().toHtmlString()\n\t},\n\t/**\n\t * Flag overlay to close on content tap\n\t * @memberof Overlay\n\t * @instance\n\t * @property {boolean}\n\t */\n\tcloseOnContentTap: false,\n\n\t/**\n\t * Shows the spinner right to the input field.\n\t * @memberof Overlay\n\t * @instance\n\t * @method\n\t */\n\tshowSpinner: function () {\n\t\tthis.$spinner.removeClass( 'hidden' );\n\t},\n\n\t/**\n\t * Hide the spinner near to the input field.\n\t * @memberof Overlay\n\t * @instance\n\t * @method\n\t */\n\thideSpinner: function () {\n\t\tthis.$spinner.addClass( 'hidden' );\n\t},\n\n\t/**\n\t * @inheritdoc\n\t * @memberof Overlay\n\t * @instance\n\t */\n\tpreRender: function () {\n\t\tvar props = this.options;\n\t\tthis.options.hasActions = props.headerButtons || props.headerActions.length;\n\t},\n\n\t/**\n\t * @inheritdoc\n\t * @memberof Overlay\n\t * @instance\n\t */\n\tpostRender: function () {\n\t\tthis.$overlayContent = this.$el.find( '.overlay-content' );\n\t\tthis.$spinner = this.$el.find( '.spinner' );\n\t\tif ( this.isIos ) {\n\t\t\tthis.$el.addClass( 'overlay-ios' );\n\t\t}\n\t\t// Truncate any text inside in the overlay header.\n\t\tthis.$el.find( '.overlay-header h2 span' ).addClass( 'truncated-text' );\n\t\tthis.$el.find( '.header-action' ).append(\n\t\t\tthis.options.headerActions.map( function ( component ) {\n\t\t\t\treturn component.$el;\n\t\t\t} )\n\t\t);\n\t},\n\n\t/**\n\t * ClickBack event handler\n\t * @memberof Overlay\n\t * @instance\n\t * @param {Object} ev event object\n\t */\n\tonExitClick: function ( ev ) {\n\t\tconst exit = function () {\n\t\t\t// FIXME: This check will be removed once ImageOverlay\n\t\t\t// is using onBeforeExit.\n\t\t\tif ( this.hideOnExitClick ) {\n\t\t\t\tthis.hide();\n\t\t\t}\n\t\t\tthis.emit( Overlay.EVENT_EXIT );\n\t\t}.bind( this );\n\t\tev.preventDefault();\n\t\tev.stopPropagation();\n\t\tif ( this.options.onBeforeExit ) {\n\t\t\tthis.options.onBeforeExit( exit );\n\t\t} else {\n\t\t\texit();\n\t\t}\n\n\t},\n\t/**\n\t * Stop clicks in the overlay from propagating to the page\n\t * (prevents non-fullscreen overlays from being closed when they're tapped)\n\t * @memberof Overlay\n\t * @instance\n\t * @param {Object} ev Event Object\n\t */\n\tstopPropagation: function ( ev ) {\n\t\tev.stopPropagation();\n\t},\n\t/**\n\t * Attach overlay to current view and show it.\n\t * @memberof Overlay\n\t * @instance\n\t */\n\tshow: function () {\n\t\tvar $html = util.getDocument();\n\n\t\tthis.scrollTop = window.pageYOffset;\n\n\t\tif ( this.fullScreen ) {\n\t\t\t$html.addClass( 'overlay-enabled' );\n\t\t\t// skip the URL bar if possible\n\t\t\twindow.scrollTo( 0, 1 );\n\t\t}\n\n\t\tif ( this.closeOnContentTap ) {\n\t\t\t$html.find( '#mw-mf-page-center' ).one( 'click', this.hide.bind( this ) );\n\t\t}\n\n\t\tthis.$el.addClass( 'visible' );\n\t},\n\t/**\n\t * Detach the overlay from the current view\n\t * @memberof Overlay\n\t * @instance\n\t * @return {boolean} Whether the overlay was successfully hidden or not\n\t */\n\thide: function () {\n\t\tvar $html = util.getDocument();\n\n\t\tif ( this.fullScreen ) {\n\t\t\t$html.removeClass( 'overlay-enabled' );\n\t\t\t// return to last known scroll position\n\t\t\twindow.scrollTo( window.pageXOffset, this.scrollTop );\n\t\t}\n\n\t\tthis.$el.detach();\n\n\t\t/**\n\t\t * Fired when the overlay is closed.\n\t\t * @event Overlay#hide\n\t\t */\n\t\tthis.emit( 'hide' );\n\n\t\treturn true;\n\t},\n\n\t/**\n\t * Show elements that are selected by the className.\n\t * Also hide .hideable elements\n\t * Can't use jQuery's hide() and show() because show() sets display: block.\n\t * And we want display: table for headers.\n\t * @memberof Overlay\n\t * @instance\n\t * @protected\n\t * @param {string} className CSS selector to show\n\t */\n\tshowHidden: function ( className ) {\n\t\tthis.$el.find( '.hideable' ).addClass( 'hidden' );\n\t\tthis.$el.find( className ).removeClass( 'hidden' );\n\t}\n} );\n\n/*\n * Fires when close button is clicked. Not to be confused with hide event.\n * @memberof Overlay\n * @event Overlay#Overlay-exit\n */\nOverlay.EVENT_EXIT = 'Overlay-exit';\n\n/**\n * Factory method for an overlay with a single child\n * @memberof Overlay\n * @instance\n * @protected\n * @param {Object} options\n * @param {View} view\n * @return {Overlay}\n */\nOverlay.make = function ( options, view ) {\n\tvar overlay = new Overlay( options );\n\toverlay.$el.find( '.overlay-content' ).append( view.$el );\n\treturn overlay;\n};\n\nmodule.exports = Overlay;\n","var\n\tutil = require( './util' ),\n\tmfExtend = require( './mfExtend' ),\n\toverlayManager = null;\n\n/**\n * Manages opening and closing overlays when the URL hash changes to one\n * of the registered values (see OverlayManager.add()).\n *\n * This allows overlays to function like real pages, with similar browser back/forward\n * and refresh behavior.\n *\n * @class OverlayManager\n * @param {Router} router\n * @param {Element} container where overlays should be managed\n */\nfunction OverlayManager( router, container ) {\n\trouter.on( 'route', this._checkRoute.bind( this ) );\n\tthis.router = router;\n\t// use an object instead of an array for entries so that we don't\n\t// duplicate entries that already exist\n\tthis.entries = {};\n\t// stack of all the open overlays, stack[0] is the latest one\n\tthis.stack = [];\n\tthis.hideCurrent = true;\n\t// Set the element that overlays will be appended to\n\tthis.container = container;\n}\n\n/**\n * Attach an event to the overlays hide event\n * @param {Overlay} overlay\n */\nfunction attachHideEvent( overlay ) {\n\toverlay.on( 'hide', function () {\n\t\toverlay.emit( '_om_hide' );\n\t} );\n}\n\nmfExtend( OverlayManager, {\n\t/**\n\t * Don't try to hide the active overlay on a route change event triggered\n\t * by hiding another overlay.\n\t * Called when hiding an overlay.\n\t * @memberof OverlayManager\n\t * @instance\n\t * @private\n\t */\n\t_onHideOverlay: function () {\n\t\tthis.hideCurrent = false;\n\n\t\tthis.router.back();\n\t},\n\n\t/** Attach overlay to DOM\n\t * @memberof OverlayManager\n\t * @instance\n\t * @private\n\t * @param {Overlay} overlay to attach\n\t*/\n\t_attachOverlay: function ( overlay ) {\n\t\tif ( !overlay.$el.parents().length ) {\n\t\t\tthis.container.appendChild( overlay.$el[0] );\n\t\t}\n\t},\n\t/**\n\t * Show the overlay and bind the '_om_hide' event to _onHideOverlay.\n\t * @memberof OverlayManager\n\t * @instance\n\t * @private\n\t * @param {Overlay} overlay to show\n\t */\n\t_show: function ( overlay ) {\n\n\t\t// if hidden using overlay (not hardware) button, update the state\n\t\toverlay.once( '_om_hide', this._onHideOverlay.bind( this ) );\n\n\t\tthis._attachOverlay( overlay );\n\t\toverlay.show();\n\t},\n\n\t/**\n\t * Hide overlay\n\t * @memberof OverlayManager\n\t * @instance\n\t * @private\n\t * @param {Overlay} overlay to hide\n\t * @return {boolean} Whether the overlay has been hidden\n\t */\n\t_hideOverlay: function ( overlay ) {\n\t\tlet result;\n\n\t\tfunction exit() {\n\t\t\tresult = true;\n\t\t}\n\t\t// remove the callback for updating state when overlay closed using\n\t\t// overlay close button\n\t\toverlay.off( '_om_hide' );\n\n\t\tif ( overlay.options && overlay.options.onBeforeExit ) {\n\t\t\toverlay.options.onBeforeExit( exit );\n\t\t} else {\n\t\t\tresult = overlay.hide();\n\t\t}\n\n\t\t// if closing prevented, reattach the callback\n\t\tif ( !result ) {\n\t\t\toverlay.once( '_om_hide', this._onHideOverlay.bind( this ) );\n\t\t}\n\n\t\treturn result;\n\t},\n\n\t/**\n\t * Show match's overlay if match is not null.\n\t * @memberof OverlayManager\n\t * @instance\n\t * @private\n\t * @param {Object|null} match Object with factory function's result. null if no match.\n\t */\n\t_processMatch: function ( match ) {\n\t\tvar factoryResult,\n\t\t\tself = this;\n\n\t\tif ( match ) {\n\t\t\tif ( match.overlay ) {\n\t\t\t\t// if the match is an overlay that was previously opened, reuse it\n\t\t\t\tself._show( match.overlay );\n\t\t\t} else {\n\t\t\t\t// else create an overlay using the factory function result (either\n\t\t\t\t// a promise or an overlay)\n\t\t\t\tfactoryResult = match.factoryResult;\n\t\t\t\t// http://stackoverflow.com/a/13075985/365238\n\t\t\t\tif ( typeof factoryResult.promise === 'function' ) {\n\t\t\t\t\tfactoryResult.then( function ( overlay ) {\n\t\t\t\t\t\tmatch.overlay = overlay;\n\t\t\t\t\t\tattachHideEvent( overlay );\n\t\t\t\t\t\tself._show( overlay );\n\t\t\t\t\t} );\n\t\t\t\t} else {\n\t\t\t\t\tmatch.overlay = factoryResult;\n\t\t\t\t\tattachHideEvent( match.overlay );\n\t\t\t\t\tself._show( factoryResult );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t/**\n\t * A callback for Router's `route` event.\n\t * @memberof OverlayManager\n\t * @instance\n\t * @private\n\t * @param {jQuery.Event} ev Event object.\n\t */\n\t_checkRoute: function ( ev ) {\n\t\tlet current = this.stack[0],\n\t\t\tmatch;\n\n\t\t// When entering an overlay for the first time,\n\t\t// the manager should remember the user's scroll position\n\t\t// overlays always open at top of page\n\t\t// and we'll want to restore it later.\n\t\t// This should happen before the call to _matchRoute which will \"show\" the overlay.\n\t\t// The Overlay has similar logic for overlays that are not managed via the overlay.\n\t\tif ( !current ) {\n\t\t\tthis.scrollTop = window.pageYOffset;\n\t\t}\n\n\t\t// if there is an overlay in the stack and it's opened, try to close it\n\t\tif (\n\t\t\tcurrent &&\n\t\t\tcurrent.overlay !== undefined &&\n\t\t\tthis.hideCurrent &&\n\t\t\t!this._hideOverlay( current.overlay )\n\t\t) {\n\t\t\t// if hide prevented, prevent route change event\n\t\t\tev.preventDefault();\n\t\t\treturn;\n\t\t}\n\n\t\tmatch = Object.keys( this.entries ).reduce( function ( m, id ) {\n\t\t\treturn m || this._matchRoute( ev.path, this.entries[ id ] );\n\t\t}.bind( this ), null );\n\n\t\tif ( !match ) {\n\t\t\t// if hidden and no new matches, reset the stack\n\t\t\tthis.stack = [];\n\t\t\t// restore the scroll position.\n\t\t\twindow.scrollTo( window.pageXOffset, this.scrollTop );\n\t\t}\n\n\t\tthis.hideCurrent = true;\n\t\tthis._processMatch( match );\n\t},\n\n\t/**\n\t * Check if a given path matches one of the existing entries and\n\t * remove it from the stack.\n\t * @memberof OverlayManager\n\t * @instance\n\t * @private\n\t * @param {string} path Path (hash) to check.\n\t * @param {Object} entry Entry object created in OverlayManager#add.\n\t * @return {Object|null} Match object with factory function's result.\n\t *  Returns null if no match.\n\t */\n\t_matchRoute: function ( path, entry ) {\n\t\tvar\n\t\t\tnext,\n\t\t\tmatch = path.match( entry.route ),\n\t\t\tprevious = this.stack[1],\n\t\t\tself = this;\n\n\t\t/**\n\t\t * Returns object to add to stack\n\t\t * @method\n\t\t * @ignore\n\t\t * @return {Object}\n\t\t */\n\t\tfunction getNext() {\n\t\t\treturn {\n\t\t\t\tpath: path,\n\t\t\t\tfactoryResult: entry.factory.apply( self, match.slice( 1 ) )\n\t\t\t};\n\t\t}\n\n\t\tif ( match ) {\n\t\t\t// if previous stacked overlay's path matches, assume we're going back\n\t\t\t// and reuse a previously opened overlay\n\t\t\tif ( previous && previous.path === path ) {\n\t\t\t\tif ( previous.overlay && previous.overlay.hasLoadError ) {\n\t\t\t\t\tself.stack.shift();\n\t\t\t\t\t// Loading of overlay failed so we want to replace it with a new\n\t\t\t\t\t// overlay (which will try to load successfully)\n\t\t\t\t\tself.stack[0] = getNext();\n\t\t\t\t\treturn self.stack[0];\n\t\t\t\t}\n\n\t\t\t\tself.stack.shift();\n\t\t\t\treturn previous;\n\t\t\t} else {\n\t\t\t\tnext = getNext();\n\t\t\t\tif ( this.stack[0] && next.path === this.stack[0].path ) {\n\t\t\t\t\t// current overlay path is same as path to check which means overlay\n\t\t\t\t\t// is attempting to refresh so just replace current overlay with new\n\t\t\t\t\t// overlay\n\t\t\t\t\tself.stack[0] = next;\n\t\t\t\t} else {\n\t\t\t\t\tself.stack.unshift( next );\n\t\t\t\t}\n\t\t\t\treturn next;\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t},\n\n\t/**\n\t * Add an overlay that should be shown for a specific fragment identifier.\n\t *\n\t * The following code will display an overlay whenever a user visits a URL that\n\t * end with '#/hi/name'. The value of `name` will be passed to the overlay.\n\t *\n\t *     @example\n\t *     overlayManager.add( /\\/hi\\/(.*)/, function ( name ) {\n\t *       var factoryResult = $.Deferred();\n\t *\n\t *       mw.using( 'mobile.HiOverlay', function () {\n\t *         var HiOverlay = M.require( 'HiOverlay' );\n\t *         factoryResult.resolve( new HiOverlay( { name: name } ) );\n\t *       } );\n\t *\n\t *       return factoryResult;\n\t *     } );\n\t *\n\t * @memberof OverlayManager\n\t * @instance\n\t * @param {RegExp} route route regular expression, optionally with parameters.\n\t * @param {Function} factory a function returning an overlay or a $.Deferred\n\t * which resolves to an overlay.\n\t */\n\tadd: function ( route, factory ) {\n\t\tvar self = this,\n\t\t\tentry = {\n\t\t\t\troute: route,\n\t\t\t\tfactory: factory\n\t\t\t};\n\n\t\tthis.entries[route] = entry;\n\t\t// Check if overlay should be shown for the current path.\n\t\t// The DOM must fully load before we can show the overlay because Overlay relies on it.\n\t\tutil.docReady( function () {\n\t\t\tself._processMatch( self._matchRoute( self.router.getPath(), entry ) );\n\t\t} );\n\t},\n\n\t/**\n\t * Replace the currently displayed overlay with a new overlay without changing the\n\t * URL. This is useful for when you want to switch overlays, but don't want to\n\t * change the back button or close box behavior.\n\t *\n\t * @memberof OverlayManager\n\t * @instance\n\t * @param {Object} overlay The overlay to display\n\t */\n\treplaceCurrent: function ( overlay ) {\n\t\tif ( this.stack.length === 0 ) {\n\t\t\tthrow new Error( 'Trying to replace OverlayManager\\'s current overlay, but stack is empty' );\n\t\t}\n\t\tthis._hideOverlay( this.stack[0].overlay );\n\t\tthis.stack[0].overlay = overlay;\n\t\tattachHideEvent( overlay );\n\t\tthis._show( overlay );\n\t}\n} );\n\n/**\n * Retrieve a singleton instance using 'mediawiki.router'.\n * @memberof OverlayManager\n * @return {OverlayManager}\n */\nOverlayManager.getSingleton = function () {\n\tif ( !overlayManager ) {\n\t\tconst container = document.createElement( 'div' );\n\t\tcontainer.className = 'mw-overlays-container';\n\t\tdocument.body.appendChild( container );\n\t\toverlayManager = new OverlayManager( mw.loader.require( 'mediawiki.router' ), container );\n\t}\n\treturn overlayManager;\n};\n\nmodule.exports = OverlayManager;\n","var\n\tHTML = mw.html,\n\tmfExtend = require( './mfExtend' ),\n\ttime = require( './time' ),\n\tutil = require( './util' ),\n\tSection = require( './Section' ),\n\tThumbnail = require( './Thumbnail' ),\n\tView = require( './View' ),\n\tHEADING_SELECTOR = mw.config.get( 'wgMFMobileFormatterHeadings', [ 'h1', 'h2', 'h3', 'h4', 'h5' ] ).join( ',' ),\n\tBLACKLISTED_THUMBNAIL_CLASS_SELECTORS = [ 'noviewer', 'metadata' ];\n\n/**\n * Mobile page view object\n *\n * @class Page\n * @uses Section\n * @extends View\n *\n * @param {Object} options Configuration options\n */\nfunction Page( options ) {\n\n\tutil.extend( this, {\n\t\toptions: options,\n\t\t// FIXME: Deprecate title property as it can be derived from titleObj using getPrefixedText\n\t\ttitle: options.title,\n\t\ttitleObj: options.titleObj,\n\t\tdisplayTitle: options.displayTitle,\n\t\turl: options.url || mw.util.getUrl( options.title ),\n\t\tid: options.id,\n\t\twikidataDescription: options.wikidataDescription,\n\t\tthumbnail: ( Object.prototype.hasOwnProperty.call( options, 'thumbnail' ) ) ?\n\t\t\toptions.thumbnail : false,\n\t\tisMissing: ( options.isMissing !== undefined ) ?\n\t\t\toptions.isMissing : options.id === 0\n\t} );\n\n\tthis.options.isBorderBox = false;\n\tthis.options.languageUrl = mw.util.getUrl( 'Special:MobileLanguages/' + this.title );\n\n\tView.call( this, this.options );\n\n\t// Fallback if no displayTitle provided\n\tif ( !this.displayTitle ) {\n\t\tthis.displayTitle = this.getDisplayTitle();\n\t}\n\n\tif ( this.thumbnail && this.thumbnail.width ) {\n\t\tthis.thumbnail.isLandscape = this.thumbnail.width > this.thumbnail.height;\n\t}\n}\n\nmfExtend( Page, View, {\n\t/**\n\t * @memberof Page\n\t * @instance\n\t * @mixes View#defaults\n\t * @property {Object} defaults Default options hash.\n\t * @property {number} defaults.id Page ID. The default value of 0 represents a\n\t * new or missing page. Be sure to override it to avoid side effects.\n\t * @property {string} defaults.title Title of the page. It includes prefix where needed and\n\t * is human readable, e.g. Talk:The man who lived.\n\t * @property {string} defaults.displayTitle HTML title of the page for display. Falls back\n\t * to defaults.title (escaped) if no value is provided. Must be safe HTML!\n\t * @property {number} defaults.namespaceNumber the number of the\n\t *  namespace the page belongs to\n\t * @property {Object} defaults.protection List of permissions as returned by API,\n\t * e.g. [{ edit: ['*'] }]\n\t * @property {Array} defaults.sections Array of {Section} objects.\n\t * @property {boolean} defaults.isMainPage Whether the page is the Main Page.\n\t * @property {boolean} defaults.isMissing Whether the page exists in the wiki.\n\t * @property {Object} defaults.thumbnail thumbnail definition corresponding to page image\n\t * @property {boolean} defaults.thumbnail.isLandscape whether the image is in\n\t *  landscape format\n\t * @property {number} defaults.thumbnail.width of image in pixels.\n\t * @property {number} defaults.thumbnail.height of image in pixels.\n\t * @property {string} defaults.thumbnail.source url for image\n\t */\n\tdefaults: {\n\t\tid: 0,\n\t\ttitle: '',\n\t\tdisplayTitle: '',\n\t\tnamespaceNumber: 0,\n\t\tprotection: {\n\t\t\tedit: [ '*' ]\n\t\t},\n\t\tsections: [],\n\t\tisMissing: false,\n\t\tisMainPage: false,\n\t\turl: undefined,\n\t\tthumbnail: {\n\t\t\tisLandscape: undefined,\n\t\t\tsource: undefined,\n\t\t\twidth: undefined,\n\t\t\theight: undefined\n\t\t}\n\t},\n\t/**\n\t * Retrieve the title that should be displayed to the user\n\t * @memberof Page\n\t * @instance\n\t * @return {string} HTML\n\t */\n\tgetDisplayTitle: function () {\n\t\treturn this.options.displayTitle || HTML.escape( this.options.title );\n\t},\n\t/**\n\t * Determine if current page is in a specified namespace\n\t * @memberof Page\n\t * @instance\n\t * @param {string} namespace Name of namespace\n\t * @return {boolean}\n\t */\n\tinNamespace: function ( namespace ) {\n\t\treturn this.options.namespaceNumber === mw.config.get( 'wgNamespaceIds' )[namespace];\n\t},\n\n\t/**\n\t * Find the heading in the page.\n\t * This has the benefit of excluding any additional h2s and h3s that may\n\t * have been added programatically.\n\t * @method\n\t * @param {number} sectionIndex as defined by the PHP parser.\n\t *  It should correspond to the section id\n\t *  used in the edit link for the section.\n\t *  Note, confusingly, this is different from section \"ID\" which is\n\t * used in methods\n\t * @return {jQuery.Object}\n\t */\n\tfindSectionHeadingByIndex: function ( sectionIndex ) {\n\t\tif ( sectionIndex < 1 ) {\n\t\t\t// negative indexes will search from the end, which is behaviour we do not want.\n\t\t\t// return an empty set when this happens.\n\t\t\treturn this.$el.find();\n\t\t} else {\n\t\t\treturn this.$el.find( HEADING_SELECTOR )\n\t\t\t\t// Headings must strictly be a child element of a section element\n\t\t\t\t// or the parser-output.\n\t\t\t\t// Not an ancestor!\n\t\t\t\t.filter( '.mw-parser-output > *, [class^=\"mf-section-\"] > *' ).eq( sectionIndex - 1 );\n\t\t}\n\t},\n\t/**\n\t * Finds all child elements that match the selector in a given section or subsection.\n\t * Returns any direct child elements that match the selector,\n\t * (i.e. searches only one level deep)\n\t * as well as any elements that match the selector within those children.\n\t * If the Page has no headings (e.g. a stub),\n\t * then the search will target all nodes within the page.\n\t *\n\t * This code should work on desktop (PHP parser HTML)\n\t * as well as mobile formatted HTML (PHP parser + MobileFormatter)\n\t * @method\n\t * @param {number} sectionIndex as defined by the PHP parser. It should correspond to\n\t *  the section id used in the edit link for the section.\n\t *  Note, confusingly, this is different from section \"ID\" which is\n\t *  used in methods\n\t * @param {string} selector to match\n\t * @return {jQuery.Object}\n\t */\n\tfindChildInSectionLead: function ( sectionIndex, selector ) {\n\t\tvar $heading, $nextHeading, $container, $lead,\n\t\t\theadingSelector = HEADING_SELECTOR;\n\n\t\tfunction withNestedChildren( $matchingNodes ) {\n\t\t\treturn $matchingNodes.find( selector ).addBack();\n\t\t}\n\n\t\tif ( sectionIndex === 0 ) {\n\t\t\t// lead is easy\n\t\t\t$lead = this.getLeadSectionElement();\n\t\t\tif ( $lead && $lead.length ) {\n\t\t\t\treturn withNestedChildren( $lead.children( selector ) );\n\t\t\t} else {\n\t\t\t\t$heading = this.findSectionHeadingByIndex( 1 );\n\t\t\t\treturn $heading.length ? withNestedChildren( $heading.prevAll( selector ) ) :\n\t\t\t\t\t// this page is a stub so search entire page\n\t\t\t\t\tthis.$el.find( selector );\n\t\t\t}\n\t\t}\n\n\t\t// find heading associated with the section by looking at its\n\t\t// index position in the article\n\t\t// section ids relate to the element position in the page and the first heading\n\t\t// lead has been dealt with above, so first heading corresponds to section 1,\n\t\t// the first heading in the article.\n\t\t$heading = this.findSectionHeadingByIndex( sectionIndex );\n\n\t\t// If section-heading is present on the heading,\n\t\t// then we know the page has been MobileFormatted\n\t\t// and that this is a wrapped section\n\t\tif ( $heading.hasClass( 'section-heading' ) ) {\n\t\t\t// get content of section\n\t\t\t$container = $heading.next();\n\t\t\t// inside section find the first heading\n\t\t\t$nextHeading = $container.find( headingSelector ).eq( 0 );\n\t\t\treturn $nextHeading.length ?\n\t\t\t\t// find all amboxes before the next heading\n\t\t\t\twithNestedChildren( $nextHeading.prevAll( selector ) ) :\n\t\t\t\t// There is no subheadings inside\n\t\t\t\t// Grab all issues in section\n\t\t\t\twithNestedChildren( $container.children( selector ) );\n\t\t} else {\n\t\t\t// the heading relates to a subsection (or unwrapped desktop section),\n\t\t\t// so grab elements between this and the next one\n\t\t\t$nextHeading = $heading.eq( 0 ).nextAll( headingSelector ).eq( 0 );\n\t\t\treturn $heading.nextUntil( $nextHeading, selector );\n\t\t}\n\t},\n\n\t/**\n\t * Get the lead section of the page view.\n\t * @memberof Page\n\t * @instance\n\t * @return {jQuery.Object|null}\n\t */\n\tgetLeadSectionElement: function () {\n\t\t/*\n\t\t * The page is formatted as follows:\n\t\t * <div id=\"bodyContent\">\n\t\t *   <!-- content of the page.. -->\n\t\t *   <div id=\"mw-content-text\">\n\t\t *     <div class=\"mf-section-0\">lead section</div>\n\t\t *     <h2></h2>\n\t\t *     <div class=\"mf-section-1\">second section</div>\n\t\t *   </div>\n\t\t * </div>\n\t\t */\n\t\tif ( this.$el.find( '.mf-section-0' ).length ) {\n\t\t\treturn this.$el.find( '.mf-section-0' );\n\t\t}\n\t\t// no lead section found\n\t\treturn null;\n\t},\n\n\t/**\n\t * Determines if content model is wikitext\n\t * @memberof Page\n\t * @instance\n\t * @return {boolean}\n\t */\n\tisWikiText: function () {\n\t\treturn mw.config.get( 'wgPageContentModel' ) === 'wikitext';\n\t},\n\n\t/**\n\t * Checks whether the current page is the main page\n\t * @memberof Page\n\t * @instance\n\t * @return {boolean}\n\t */\n\tisMainPage: function () {\n\t\treturn this.options.isMainPage;\n\t},\n\t/**\n\t * Checks whether the current page is watched\n\t * @memberof Page\n\t * @instance\n\t * @return {boolean}\n\t */\n\tisWatched: function () {\n\t\treturn this.options.isWatched;\n\t},\n\n\t/**\n\t * Return the latest revision id for this page\n\t * @memberof Page\n\t * @instance\n\t * @return {number}\n\t */\n\tgetRevisionId: function () {\n\t\treturn this.options.revId;\n\t},\n\n\t/**\n\t * Return prefixed page title\n\t * @memberof Page\n\t * @instance\n\t * @return {string}\n\t */\n\tgetTitle: function () {\n\t\treturn this.options.title;\n\t},\n\n\t/**\n\t * Return page id\n\t * @memberof Page\n\t * @instance\n\t * @return {number}\n\t */\n\tgetId: function () {\n\t\treturn this.options.id;\n\t},\n\n\t/**\n\t * return namespace id\n\t * @memberof Page\n\t * @instance\n\t * @return {number} namespace Number\n\t */\n\tgetNamespaceId: function () {\n\t\tvar nsId,\n\t\t\targs = this.options.title.split( ':' );\n\n\t\tif ( args[1] ) {\n\t\t\tnsId = mw.config.get( 'wgNamespaceIds' )[ args[0].toLowerCase().replace( ' ', '_' ) ] || 0;\n\t\t} else {\n\t\t\tnsId = 0;\n\t\t}\n\t\treturn nsId;\n\t},\n\n\t/**\n\t * Determines if current page is a talk page\n\t * @memberof Page\n\t * @instance\n\t * @return {boolean} Whether the page is a talk page or not\n\t */\n\tisTalkPage: function () {\n\t\tvar ns = this.getNamespaceId();\n\t\t// all talk pages are odd Numbers (except the case of special pages)\n\t\treturn ns > 0 && ns % 2 === 1;\n\t},\n\n\t/**\n\t * @inheritdoc\n\t * @memberof Page\n\t * @instance\n\t */\n\tpreRender: function () {\n\t\tthis.sections = [];\n\t\tthis._sectionLookup = {};\n\t\tthis.title = this.options.title;\n\n\t\tthis.options.sections.forEach( function ( sectionData ) {\n\t\t\tvar section = new Section( sectionData );\n\t\t\tthis.sections.push( section );\n\t\t\tthis._sectionLookup[section.id] = section;\n\t\t}.bind( this ) );\n\t},\n\n\t/**\n\t * Return all the thumbnails in the article.\n\t * Images which have a class or link container (.image|.thumbimage)\n\t * that matches one of the items of the constant BLACKLISTED_THUMBNAIL_CLASS_SELECTORS\n\t * will be excluded.\n\t * A thumbnail nested inside one of these classes will still be returned.\n\t * e.g. `<div class=\"noviewer\"><a class=\"image\"><img></a></div>` is not a valid thumbnail\n\t * `<a class=\"image noviewer\"><img></a>` is not a valid thumbnail\n\t * `<a class=\"image\"><img class=\"noviewer\"></a>` is not a valid thumbnail\n\t * @memberof Page\n\t * @instance\n\t * @return {Thumbnail[]}\n\t */\n\tgetThumbnails: function () {\n\t\tvar $thumbs,\n\t\t\t$el = this.$el,\n\t\t\tblacklistSelector = '.' + BLACKLISTED_THUMBNAIL_CLASS_SELECTORS.join( ',.' ),\n\t\t\tthumbs = [];\n\n\t\tif ( !this._thumbs ) {\n\t\t\t$thumbs = $el.find( 'a.image, a.thumbimage' )\n\t\t\t\t.not( blacklistSelector );\n\n\t\t\t$thumbs.each( function () {\n\t\t\t\tvar $a = $el.find( this ),\n\t\t\t\t\t$lazyImage = $a.find( '.lazy-image-placeholder' ),\n\t\t\t\t\t// Parents need to be checked as well.\n\t\t\t\t\tvalid = $a.parents( blacklistSelector ).length === 0 &&\n\t\t\t\t\t\t$a.find( blacklistSelector ).length === 0,\n\t\t\t\t\tlegacyMatch = $a.attr( 'href' ).match( /title=([^/&]+)/ ),\n\t\t\t\t\tmatch = $a.attr( 'href' ).match( /[^/]+$/ );\n\n\t\t\t\t// filter out invalid lazy loaded images if so far image is valid\n\t\t\t\tif ( $lazyImage.length && valid ) {\n\t\t\t\t\t// if the regex matches it means the image has one of the classes\n\t\t\t\t\t// thus we must invert the result\n\t\t\t\t\tvalid = !new RegExp( '\\\\b(' + BLACKLISTED_THUMBNAIL_CLASS_SELECTORS.join( '|' ) + ')\\\\b' )\n\t\t\t\t\t\t.test( $lazyImage.data( 'class' ) );\n\t\t\t\t}\n\n\t\t\t\tif ( valid && ( legacyMatch || match ) ) {\n\t\t\t\t\tthumbs.push(\n\t\t\t\t\t\tnew Thumbnail( {\n\t\t\t\t\t\t\tel: $a,\n\t\t\t\t\t\t\tfilename: decodeURIComponent(\n\t\t\t\t\t\t\t\tlegacyMatch ? legacyMatch[1] : match[0]\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t} )\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} );\n\t\t\tthis._thumbs = thumbs;\n\t\t}\n\t\treturn this._thumbs;\n\t},\n\n\t/**\n\t * FIXME: Change function signature to take the anchor of the heading\n\t * @memberof Page\n\t * @instance\n\t * @param {string} id of the section as defined by MobileFormatter.\n\t * Note, that currently, this is different from\n\t * the PHP parser in that it relates to top-level sections.\n\t * For example, mf-section-1 would relate to section 1. See FIXME.\n\t * @return {Section}\n\t */\n\tgetSection: function ( id ) {\n\t\treturn this._sectionLookup[ id ];\n\t},\n\n\t/**\n\t * Obtain the list of high level (and grouped) sections.\n\t * Note that this list will not include subsections.\n\t * @memberof Page\n\t * @instance\n\t * @return {Array} of Section instances\n\t */\n\tgetSections: function () {\n\t\treturn this.sections;\n\t},\n\n\t/**\n\t * Returns a jQuery object representing all redlinks on the page.\n\t * @memberof Page\n\t * @instance\n\t * @return {jQuery.Object}\n\t */\n\tgetRedLinks: function () {\n\t\treturn this.$el.find( '.new' );\n\t}\n} );\n\n/**\n * Create a Page object from an API response.\n *\n * @memberof Page\n * @param {Object} resp as representing a page in the API\n * @return {Page}\n */\nPage.newFromJSON = function ( resp ) {\n\tvar revision, displayTitle,\n\t\tthumb = resp.thumbnail,\n\t\tpageprops = resp.pageprops || {\n\t\t\tdisplaytitle: HTML.escape( resp.title )\n\t\t},\n\t\tterms = resp.terms;\n\n\tif ( pageprops || terms ) {\n\t\t// The label is either the display title or the label pageprop\n\t\t// (the latter used by Wikidata)\n\t\t// Long term we want to consolidate these.\n\t\t// Note that pageprops.displaytitle is HTML, while\n\t\t// terms.label[0] is plain text.\n\t\tdisplayTitle = terms && terms.label ?\n\t\t\tHTML.escape( terms.label[0] ) : pageprops.displaytitle;\n\t}\n\t// Add Wikidata descriptions if available (T101719)\n\tresp.wikidataDescription = resp.description || undefined;\n\n\tif ( thumb ) {\n\t\tresp.thumbnail.isLandscape = thumb.width > thumb.height;\n\t}\n\n\t// page may or may not exist.\n\tif ( resp.revisions && resp.revisions[0] ) {\n\t\trevision = resp.revisions[0];\n\t\tresp.lastModified = time.getLastModifiedMessage(\n\t\t\tnew Date( revision.timestamp ).getTime() / 1000,\n\t\t\trevision.user\n\t\t);\n\t}\n\n\treturn new Page(\n\t\tutil.extend( resp, {\n\t\t\tid: resp.pageid,\n\t\t\tisMissing: !!resp.missing,\n\t\t\turl: mw.util.getUrl( resp.title ),\n\t\t\tdisplayTitle: displayTitle // this is HTML!\n\t\t} )\n\t);\n};\n\n/**\n * Selector for matching headings\n *\n * @memberof Page\n */\nPage.HEADING_SELECTOR = HEADING_SELECTOR;\n\nmodule.exports = Page;\n","var sectionTemplate = mw.template.get( 'mobile.startup', 'Section.hogan' ),\n\tutil = require( './util.js' ),\n\tPage = require( './Page' ),\n\tactionParams = require( './actionParams' ),\n\tcache = {};\n\n/**\n * Add child to listOfSections if the level of child is the same as the last\n * child of listOfSections, otherwise add it to the children of the last\n * section of listOfSections. If listOfSections is empty, just add child to it.\n * @private\n * @param {Array} listOfSections - Array of section ids\n * @param {Object} child - Section to be added to listOfSections\n */\nfunction assignToParent( listOfSections, child ) {\n\tvar section;\n\tif ( listOfSections.length === 0 ) {\n\t\tlistOfSections.push( child );\n\t} else {\n\t\t// take a look at the last child\n\t\tsection = listOfSections[listOfSections.length - 1];\n\t\t// If the level is the same as another section in this list it is a sibling\n\t\tif ( parseInt( section.level, 10 ) === parseInt( child.level, 10 ) ) {\n\t\t\tlistOfSections.push( child );\n\t\t} else {\n\t\t\t// Otherwise take a look at that sections children recursively\n\t\t\tassignToParent( section.subsections, child );\n\t\t}\n\t}\n}\n\n/**\n * Order sections hierarchically\n * @private\n * @param {Array} sections Array of section objects created from response HTML\n * @return {Array} Ordered array of sections\n */\nfunction transformSections( sections ) {\n\tvar\n\t\tsectionLevels = sections.map( function ( s ) {\n\t\t\treturn s.level;\n\t\t} ),\n\t\texistingSectionLevels = sectionLevels.filter( function ( level ) {\n\t\t\treturn !!level;\n\t\t} ),\n\t\tcollapseLevel = Math.min.apply( this, existingSectionLevels ).toString(),\n\t\tlastSection,\n\t\tresult = [];\n\n\t// if the first section level is not equal to collapseLevel, this first\n\t// section will not have a parent and will be appended to the result.\n\tsections.forEach( function ( section ) {\n\t\tif ( section.line !== undefined ) {\n\t\t\tsection.line = section.line.replace( /<\\/?a\\b[^>]*>/g, '' );\n\t\t}\n\t\tsection.subsections = [];\n\n\t\tif (\n\t\t\t!lastSection ||\n\t\t\t(\n\t\t\t\t!section.level ||\n\t\t\t\tsection.level === collapseLevel\n\t\t\t) ||\n\t\t\t// make sure lastSections first child's level is bigger than section.level\n\t\t\t(\n\t\t\t\tlastSection.subsections.length &&\n\t\t\t\tlastSection.subsections[0].level > section.level\n\t\t\t) ||\n\t\t\t// also make sure section.level is not bigger than the lastSection.level\n\t\t\t(\n\t\t\t\tlastSection.level &&\n\t\t\t\tlastSection.level >= section.level\n\t\t\t)\n\t\t) {\n\t\t\tresult.push( section );\n\t\t\tlastSection = section;\n\t\t} else {\n\t\t\tassignToParent( lastSection.subsections, section );\n\t\t\tlastSection.text += sectionTemplate.render( section );\n\t\t}\n\t} );\n\n\treturn result;\n}\n\n/**\n * API for providing Page data\n * @class PageGateway\n * @param {mw.Api} api\n */\nfunction PageGateway( api ) {\n\tthis.api = api;\n}\n\nPageGateway.prototype = {\n\t/**\n\t * Retrieve the sections of a page\n\t * @memberof PageGateway\n\t * @instance\n\t * @param {string} title the title of the page to retrieve sections for\n\t * @return {JQuery.Promise}\n\t */\n\tgetSections: function ( title ) {\n\t\tvar promise = util.Deferred();\n\t\tthis.getPage( title ).then( function ( pageData ) {\n\t\t\tvar page = new Page( pageData );\n\t\t\tpromise.resolve( page.getSections() );\n\t\t}, function ( resp ) {\n\t\t\t// If the API returns the error code 'missingtitle', that means the\n\t\t\t// talk page doesn't exist yet.\n\t\t\tif ( resp === 'missingtitle' ) {\n\t\t\t\tpromise.resolve( [] );\n\t\t\t} else {\n\t\t\t\tpromise.reject();\n\t\t\t}\n\t\t} );\n\t\treturn promise.promise();\n\t},\n\t/**\n\t * Retrieve a page from the api\n\t * @memberof PageGateway\n\t * @instance\n\t * @param {string} title the title of the page to be retrieved\n\t * @param {string} [endpoint] an alternative api url to retrieve the page from\n\t * @param {boolean} [leadOnly] When set only the lead section content is returned\n\t * @return {jQuery.Deferred} with parameter page data that can be passed to a Page view\n\t */\n\tgetPage: function ( title, endpoint, leadOnly ) {\n\t\tvar timestamp,\n\t\t\td = util.Deferred(),\n\t\t\tparams = endpoint ? {\n\t\t\t\turl: endpoint,\n\t\t\t\tdataType: 'jsonp'\n\t\t\t} : {},\n\t\t\tprotection = {\n\t\t\t\tedit: [ '*' ]\n\t\t\t};\n\n\t\tutil.extend( params,\n\t\t\tactionParams( {\n\t\t\t\taction: 'mobileview',\n\t\t\t\tpage: title,\n\t\t\t\tvariant: mw.config.get( 'wgPageContentLanguage' ),\n\t\t\t\tredirect: 'yes',\n\t\t\t\tprop: 'id|sections|text|lastmodified|lastmodifiedby|languagecount|hasvariants|protection|displaytitle|revision',\n\t\t\t\tnoheadings: 'yes',\n\t\t\t\tsectionprop: 'level|line|anchor',\n\t\t\t\tsections: leadOnly ? 0 : 'all'\n\t\t\t} )\n\t\t);\n\n\t\tif ( !cache[title] ) {\n\t\t\tcache[title] = this.api.get( params ).then( function ( resp ) {\n\t\t\t\tvar sections, lastModified, resolveObj, mv;\n\n\t\t\t\tif ( resp.error ) {\n\t\t\t\t\treturn d.reject( resp.error );\n\t\t\t\t} else if ( !resp.mobileview.sections ) {\n\t\t\t\t\treturn d.reject( 'No sections' );\n\t\t\t\t} else {\n\t\t\t\t\tmv = resp.mobileview;\n\t\t\t\t\tsections = transformSections( mv.sections );\n\t\t\t\t\t// Assume the timestamp is in the form TS_ISO_8601\n\t\t\t\t\t// and we don't care about old browsers\n\t\t\t\t\t// change to seconds to be consistent with PHP\n\t\t\t\t\ttimestamp = new Date( mv.lastmodified ).getTime() / 1000;\n\t\t\t\t\tlastModified = mv.lastmodifiedby;\n\n\t\t\t\t\t// FIXME: [API] the API sometimes returns an object and sometimes an array\n\t\t\t\t\t// There are various quirks with the format of protection level\n\t\t\t\t\t// as returned by api.\n\t\t\t\t\t// Also it is usually incomplete - if something is missing this means\n\t\t\t\t\t// that it has no protection level.\n\t\t\t\t\t// When an array this means there is no protection level set.\n\t\t\t\t\t// To keep the data type consistent either use the predefined\n\t\t\t\t\t// protection level,\n\t\t\t\t\t// or extend it with what is returned by API.\n\t\t\t\t\tprotection = Array.isArray( mv.protection ) ?\n\t\t\t\t\t\tprotection :\n\t\t\t\t\t\tutil.extend( protection, mv.protection );\n\n\t\t\t\t\tresolveObj = {\n\t\t\t\t\t\ttitle: title,\n\t\t\t\t\t\tid: mv.id,\n\t\t\t\t\t\trevId: mv.revId,\n\t\t\t\t\t\tprotection: protection,\n\t\t\t\t\t\tlead: sections[0].text,\n\t\t\t\t\t\tsections: sections.slice( 1 ),\n\t\t\t\t\t\tisMainPage: mv.mainpage !== undefined,\n\t\t\t\t\t\thistoryUrl: mw.util.getUrl( title, {\n\t\t\t\t\t\t\taction: 'history'\n\t\t\t\t\t\t} ),\n\t\t\t\t\t\tlastModifiedTimestamp: timestamp,\n\t\t\t\t\t\tlanguageCount: mv.languagecount,\n\t\t\t\t\t\thasVariants: mv.hasvariants !== undefined,\n\t\t\t\t\t\tdisplayTitle: mv.displaytitle\n\t\t\t\t\t};\n\t\t\t\t\t// Add non-anonymous user information\n\t\t\t\t\tif ( lastModified ) {\n\t\t\t\t\t\tutil.extend( resolveObj, {\n\t\t\t\t\t\t\tlastModifiedUserName: lastModified.name,\n\t\t\t\t\t\t\tlastModifiedUserGender: lastModified.gender\n\t\t\t\t\t\t} );\n\t\t\t\t\t}\n\t\t\t\t\t// FIXME: Return a Page class here\n\t\t\t\t\treturn resolveObj;\n\t\t\t\t}\n\t\t\t}, function ( msg ) {\n\t\t\t\treturn d.reject( msg );\n\t\t\t} );\n\t\t}\n\n\t\treturn cache[title];\n\t},\n\n\t/**\n\t * Invalidate the internal cache for a given page\n\t * @memberof PageGateway\n\t * @instance\n\t * @param {string} title the title of the page who's cache you want to invalidate\n\t */\n\tinvalidatePage: function ( title ) {\n\t\tdelete cache[title];\n\t},\n\n\t/**\n\t * Gets language variant list for a page; helper function for getPageLanguages()\n\t * @memberof PageGateway\n\t * @instance\n\t * @private\n\t * @param  {string} title Name of the page to obtain variants for\n\t * @param  {Object} data Data from API\n\t * @return {Array|boolean} List of language variant objects or false if no variants exist\n\t */\n\t_getLanguageVariantsFromApiResponse: function ( title, data ) {\n\t\tvar generalData = data.query.general,\n\t\t\tvariantPath = generalData.variantarticlepath,\n\t\t\tvariants = [];\n\n\t\tif ( !generalData.variants ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Create the data object for each variant and store it\n\t\tObject.keys( generalData.variants ).forEach( function ( index ) {\n\t\t\tvar item = generalData.variants[ index ],\n\t\t\t\tvariant = {\n\t\t\t\t\tautonym: item.name,\n\t\t\t\t\tlang: item.code\n\t\t\t\t};\n\n\t\t\tif ( variantPath ) {\n\t\t\t\tvariant.url = variantPath\n\t\t\t\t\t.replace( '$1', title )\n\t\t\t\t\t.replace( '$2', item.code );\n\t\t\t} else {\n\t\t\t\tvariant.url = mw.util.getUrl( title, {\n\t\t\t\t\tvariant: item.code\n\t\t\t\t} );\n\t\t\t}\n\t\t\tvariants.push( variant );\n\t\t} );\n\n\t\treturn variants;\n\t},\n\n\t/**\n\t * Retrieve available languages for a given title\n\t * @memberof PageGateway\n\t * @instance\n\t * @param {string} title the title of the page languages should be retrieved for\n\t * @param {string} [language] when provided the names of the languages returned\n\t *  will be translated additionally into this language.\n\t * @return {jQuery.Deferred} which is called with an object containing langlinks\n\t * and variant links as defined @ https://en.m.wikipedia.org/w/api.php?action=help&modules=query%2Blanglinks\n\t */\n\tgetPageLanguages: function ( title, language ) {\n\t\tvar self = this,\n\t\t\targs = actionParams( {\n\t\t\t\tmeta: 'siteinfo',\n\t\t\t\tsiprop: 'general',\n\t\t\t\tprop: 'langlinks',\n\t\t\t\tlllimit: 'max',\n\t\t\t\ttitles: title\n\t\t\t} );\n\n\t\tif ( language ) {\n\t\t\targs.llprop = 'url|autonym|langname';\n\t\t\targs.llinlanguagecode = language;\n\t\t} else {\n\t\t\targs.llprop = 'url|autonym';\n\t\t}\n\t\treturn this.api.get( args ).then( function ( resp ) {\n\t\t\treturn {\n\t\t\t\tlanguages: resp.query.pages[0].langlinks || [],\n\t\t\t\tvariants: self._getLanguageVariantsFromApiResponse( title, resp )\n\t\t\t};\n\t\t}, function () {\n\t\t\treturn util.Deferred().reject();\n\t\t} );\n\t},\n\n\t/**\n\t * Extract sections from headings in $el\n\t * @memberof PageGateway\n\t * @instance\n\t * @private\n\t * @param {jQuery.Object} $el object from which sections are extracted\n\t * @return {Array} Array of section objects created from headings in $el\n\t * FIXME: Where's a better place for getSectionsFromHTML and this function to live?\n\t * Answer: Possibly Page.js\n\t */\n\t_getAPIResponseFromHTML: function ( $el ) {\n\t\t// FIXME: use Page.HEADING_SELECTOR\n\t\tvar $headings = $el.find( 'h1,h2,h3,h4,h5,h6' ),\n\t\t\tsections = [];\n\n\t\t$headings.each( function () {\n\t\t\tvar level = this.tagName.substr( 1 ),\n\t\t\t\t$span = $el.find( this ).find( '.mw-headline' );\n\n\t\t\tif ( $span.length ) {\n\t\t\t\tsections.push( {\n\t\t\t\t\tlevel: level,\n\t\t\t\t\tline: $span.html(),\n\t\t\t\t\tanchor: $span.attr( 'id' ) || '',\n\t\t\t\t\ttext: ''\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\t\treturn sections;\n\t},\n\n\t/**\n\t * Order sections hierarchically\n\t * @memberof PageGateway\n\t * @instance\n\t * @param {jQuery.Object} $el object from which sections are extracted\n\t * @return {Array} Ordered array of sections\n\t */\n\tgetSectionsFromHTML: function ( $el ) {\n\t\treturn transformSections( this._getAPIResponseFromHTML( $el ) );\n\t}\n};\n\nmodule.exports = PageGateway;\n","var\n\tmfExtend = require( './mfExtend' ),\n\tView = require( './View' ),\n\tbrowser = require( './Browser' ).getSingleton();\n\n/**\n * List of items page view\n * @class PageList\n * @extends View\n */\nfunction PageList() {\n\tView.apply( this, arguments );\n}\n\nmfExtend( PageList, View, {\n\t/**\n\t * @memberof PageList\n\t * @instance\n\t * @mixes View#defaults\n\t * @property {Object} defaults Default options hash.\n\t * @property {Page[]} defaults.pages Array of Page objects. These should match\n\t *                              the Page model and not necessarily the\n\t *                              underlying API format used.\n\t * E.g. [\n\t *   {\n\t *     heading: \"<strong>C</strong>laude Monet\",\n\t *     id: undefined,\n\t *     title: \"Claude Monet\",\n\t *     displayTitle: \"<i>Claude Monet</i>\",\n\t *     url: \"/wiki/Claude_Monet\",\n\t *     thumbnail: {\n\t *       height: 62,\n\t *       source: \"http://127.0.0.1:8080/images/thumb/thumb.jpg\",\n\t *       width: 80,\n\t *       isLandscape: true\n\t *     }\n\t *   }\n\t * ]\n\t */\n\tdefaults: {\n\t\tpages: []\n\t},\n\t/**\n\t * Render page images for the existing page list. Assumes no page images have been loaded.\n\t * @memberof PageList\n\t * @instance\n\t */\n\trenderPageImages: function () {\n\t\tvar self = this;\n\n\t\tsetTimeout( function () {\n\t\t\tself.$el.find( '.list-thumb' ).each( function () {\n\t\t\t\tvar style = self.$el.find( this ).data( 'style' );\n\t\t\t\tself.$el.find( this ).attr( 'style', style );\n\t\t\t} );\n\t\t\t// Delay an unnecessary load of images on mobile (slower?) connections\n\t\t\t// In particular on search results which can be regenerated quickly.\n\t\t}, browser.isWideScreen() ? 0 : 1000 );\n\t},\n\t/**\n\t * @inheritdoc\n\t * @memberof PageList\n\t * @instance\n\t */\n\tpostRender: function () {\n\t\tthis.renderPageImages();\n\t},\n\ttemplate: mw.template.get( 'mobile.startup', 'PageList.hogan' ),\n\t/**\n\t * @memberof PageList\n\t * @instance\n\t */\n\ttemplatePartials: {\n\t\t// The server uses a very different structure in\n\t\t// SpecialMobileEditWatchlist.getLineHtml(). Be aware of these differences\n\t\t// when updating server rendered items.\n\t\titem: mw.template.get( 'mobile.startup', 'PageListItem.hogan' )\n\t}\n} );\n\nmodule.exports = PageList;\n","var\n\tmfExtend = require( './mfExtend' ),\n\tutil = require( './util' ),\n\tView = require( './View' );\n\n/**\n * An abstract class for a {@link View} that comprises a simple panel.\n * @class Panel\n * @extends View\n *\n * @param {Object} [params] Configuration options\n */\nfunction Panel( params ) {\n\tView.call( this, util.extend(\n\t\t{ className: 'panel' },\n\t\tparams,\n\t\t{ events: util.extend( { 'click .cancel': 'onCancel' }, ( params || {} ).events ) } )\n\t);\n}\n\nmfExtend( Panel, View, {\n\t// in milliseconds\n\tminHideDelay: 10,\n\n\t/**\n\t * Cancel event handler\n\t * @memberof Panel\n\t * @instance\n\t * @param {Object} ev Event Object\n\t */\n\tonCancel: function ( ev ) {\n\t\tev.preventDefault();\n\t\tthis.hide();\n\t},\n\n\t/**\n\t * Shows panel after a slight delay\n\t * @memberof Panel\n\t * @instance\n\t * @method\n\t */\n\tshow: function () {\n\t\tvar self = this;\n\n\t\tif ( !self.isVisible() ) {\n\t\t\t// use setTimeout to allow the browser to redraw if render() was called\n\t\t\t// just before show(); this is important for animations to work\n\t\t\t// (0ms doesn't work on Firefox, 10ms is enough)\n\t\t\t//\n\t\t\t// FIXME: setTimeout should be reconsidered in T209129\n\t\t\tsetTimeout( function () {\n\t\t\t\tself.$el.addClass( 'visible animated' );\n\t\t\t\tself.emit( 'show' );\n\t\t\t}, self.minHideDelay );\n\t\t}\n\t},\n\n\t/**\n\t * Hides panel\n\t * @memberof Panel\n\t * @instance\n\t */\n\thide: function () {\n\t\tvar self = this;\n\n\t\t// see comment in show()\n\t\tsetTimeout( function () {\n\t\t\tself.$el.removeClass( 'visible' );\n\t\t\tself.emit( 'hide' );\n\t\t}, self.minHideDelay );\n\t},\n\n\t/**\n\t * Determines if panel is visible\n\t * @memberof Panel\n\t * @instance\n\t * @return {boolean} Panel is visible\n\t */\n\tisVisible: function () {\n\t\treturn this.$el.hasClass( 'visible' );\n\t},\n\n\t/**\n\t * Shows or hides panel\n\t * @memberof Panel\n\t * @instance\n\t */\n\ttoggle: function () {\n\t\tif ( this.isVisible() ) {\n\t\t\tthis.hide();\n\t\t} else {\n\t\t\tthis.show();\n\t\t}\n\t}\n} );\n\nmodule.exports = Panel;\n","var util = require( './util' ),\n\tmfExtend = require( './mfExtend' );\n\n/**\n * Class to assist a view in implementing infinite scrolling on some DOM\n * element. This module itself is only responsible for emitting an Event when\n * the bottom of an Element is scrolled to.\n *\n * @class ScrollEndEventEmitter\n * @mixins OO.EventEmitter\n *\n * Use this class in a view to help it do infinite scrolling.\n *\n * 1. Initialize it in the constructor `initialize` and listen to the\n *   EVENT_SCROLL_END event it emits (and call your loading function then)\n * 2. On preRender (once we have the DOM element) set it into the infinite\n *   scrolling object and disable it until we've loaded.\n * 3. Once you have loaded the list and put it in the DOM, enable the\n *   infinite scrolling detection.\n *   * Everytime the scroller detection triggers a load, it auto disables\n *     to not trigger multiple times. After you have loaded, manually\n *     re-enable it.\n *\n * Example:\n *     @example\n *     <code>\n *       var\n *         mfExtend = require( './mfExtend' ),\n *         ScrollEndEventEmitter = require( './ScrollEndEventEmitter' ),\n *         eventBus = require( './eventBusSingleton' );\n *       mfExtend( PhotoList, View, {\n *         //...\n *         initialize: function ( options ) {\n *           this.gateway = new PhotoListGateway( {\n *             username: options.username\n *           } );\n *           // 1. Set up infinite scroll helper and listen to events\n *           this.scrollEndEventEmitter = new ScrollEndEventEmitter( eventBus, 1000 );\n *           this.scrollEndEventEmitter.on( ScrollEndEventEmitter.EVENT_SCROLL_END,\n *             this._loadPhotos.bind( this ) );\n *           View.prototype.initialize.apply( this, arguments );\n *         },\n *         preRender: function () {\n *           // 2. Disable until we've got the list rendered and set DOM el\n *           this.scrollEndEventEmitter.setElement( this.$el );\n *           this.scrollEndEventEmitter.disable();\n *         },\n *         _loadPhotos: function () {\n *           var self = this;\n *           this.gateway.getPhotos().then( function ( photos ) {\n *             // load photos into the DOM ...\n *             // 3. and (re-)enable infinite scrolling\n *             self.scrollEndEventEmitter.enable();\n *           } );\n *         }\n *       } );\n *     </code>\n *\n * @fires ScrollEndEventEmitter#ScrollEndEventEmitter-scrollEnd\n * @param {Object} eventBus object to listen for scroll:throttled events\n * @param {number} [threshold=100] distance in pixels used to calculate if scroll\n * position is near the end of the $el\n */\nfunction ScrollEndEventEmitter( eventBus, threshold ) {\n\tthis.threshold = threshold || 100;\n\tthis.eventBus = eventBus;\n\tthis.enable();\n\tOO.EventEmitter.call( this );\n}\nOO.mixinClass( ScrollEndEventEmitter, OO.EventEmitter );\n\n/**\n * Fired when scroll bottom has been reached.\n * @event ScrollEndEventEmitter#ScrollEndEventEmitter-scrollEnd\n */\nScrollEndEventEmitter.EVENT_SCROLL_END = 'ScrollEndEventEmitter-scrollEnd';\n\nmfExtend( ScrollEndEventEmitter, {\n\t/**\n\t * Listen to scroll on window and notify this._onScroll\n\t * @memberof ScrollEndEventEmitter\n\t * @instance\n\t * @private\n\t */\n\t_bindScroll: function () {\n\t\tif ( !this._scrollHandler ) {\n\t\t\tthis._scrollHandler = this._onScroll.bind( this );\n\t\t\tthis.eventBus.on( 'scroll:throttled', this._scrollHandler );\n\t\t}\n\t},\n\t/**\n\t * Unbind scroll handler\n\t * @memberof ScrollEndEventEmitter\n\t * @instance\n\t * @private\n\t */\n\t_unbindScroll: function () {\n\t\tif ( this._scrollHandler ) {\n\t\t\tthis.eventBus.off( 'scroll:throttled', this._scrollHandler );\n\t\t\tthis._scrollHandler = null;\n\t\t}\n\t},\n\t/**\n\t * Scroll handler. Triggers load event when near the end of the container.\n\t * @memberof ScrollEndEventEmitter\n\t * @instance\n\t * @private\n\t */\n\t_onScroll: function () {\n\t\tif ( this.$el && this.enabled && this.scrollNearEnd() ) {\n\t\t\t// Disable when triggering an event. Won't trigger again until\n\t\t\t// re-enabled.\n\t\t\tthis.disable();\n\t\t\tthis.emit( ScrollEndEventEmitter.EVENT_SCROLL_END );\n\t\t}\n\t},\n\t/**\n\t * Is the scroll position near the end of the container element?\n\t * @memberof ScrollEndEventEmitter\n\t * @instance\n\t * @private\n\t * @return {boolean}\n\t */\n\tscrollNearEnd: function () {\n\t\tvar $window = util.getWindow(),\n\t\t\tscrollBottom = $window.scrollTop() + $window.height(),\n\t\t\tendPosition = this.$el.offset().top + this.$el.outerHeight();\n\t\treturn scrollBottom + this.threshold > endPosition;\n\t},\n\t/**\n\t * Enable the ScrollEndEventEmitter so that it triggers events.\n\t * @memberof ScrollEndEventEmitter\n\t * @instance\n\t */\n\tenable: function () {\n\t\tthis.enabled = true;\n\t\tthis._bindScroll();\n\t},\n\t/**\n\t * Disable the ScrollEndEventEmitter so that it doesn't trigger events.\n\t * @memberof ScrollEndEventEmitter\n\t * @instance\n\t */\n\tdisable: function () {\n\t\tthis.enabled = false;\n\t\tthis._unbindScroll();\n\t},\n\t/**\n\t * Set the element to compare to scroll position to\n\t * @memberof ScrollEndEventEmitter\n\t * @instance\n\t * @param {jQuery.Object} $el jQuery element where we want to listen for\n\t * scroll end.\n\t */\n\tsetElement: function ( $el ) {\n\t\tthis.$el = $el;\n\t}\n} );\n\nmodule.exports = ScrollEndEventEmitter;\n","var\n\tmfExtend = require( './mfExtend' ),\n\ticons = require( './icons' ),\n\tView = require( './View' );\n\n/**\n * Builds a section of a page\n * @class Section\n * @extends View\n *\n * @param {Object} options Configuration options\n */\nfunction Section( options ) {\n\tvar self = this;\n\toptions.tag = 'h' + options.level;\n\tthis.line = options.line;\n\tthis.text = options.text;\n\tthis.hasReferences = options.hasReferences || false;\n\tthis.id = options.id || null;\n\tthis.anchor = options.anchor;\n\tthis.subsections = [];\n\t( options.subsections || [] ).forEach( function ( section ) {\n\t\tself.subsections.push( new Section( section ) );\n\t} );\n\tView.call( this, options );\n}\n\nmfExtend( Section, View, {\n\ttemplate: mw.template.get( 'mobile.startup', 'Section.hogan' ),\n\t/**\n\t * @memberof Section\n\t * @instance\n\t * @mixes View#defaults\n\t * @property {Object} defaults Default options hash.\n\t * @property {string} defaults.text Section text.\n\t * @property {string} defaults.spinner HTML of the spinner icon.\n\t */\n\tdefaults: {\n\t\tline: undefined,\n\t\ttext: '',\n\t\tspinner: icons.spinner().toHtmlString()\n\t}\n} );\n\nmodule.exports = Section;\n","var\n\tmfExtend = require( './mfExtend' ),\n\tutil = require( './util' ),\n\tView = require( './View' );\n\n/**\n * Representation of a thumbnail\n *\n * @class Thumbnail\n * @extends View\n * @param {Object} options\n */\nfunction Thumbnail( options ) {\n\tView.call( this,\n\t\tutil.extend( { isBorderBox: false }, options )\n\t);\n}\n\nmfExtend( Thumbnail, View, {\n\t/**\n\t * @memberof Thumbnail\n\t * @instance\n\t * @mixes View#defaults\n\t * @property {Object} defaults Default options hash.\n\t * @property {string} defaults.filename uri decoded filename including File: prefix\n\t *  associated with thumbnail\n\t */\n\tdefaults: {\n\t\tfilename: undefined\n\t},\n\t/**\n\t * @inheritdoc\n\t * @memberof Thumbnail\n\t * @instance\n\t */\n\tpostRender: function () {\n\t\tthis.options.description = this.$el.siblings( '.thumbcaption' ).text();\n\t},\n\t/**\n\t * Obtain description for thumbnail\n\t * @memberof Thumbnail\n\t * @instance\n\t * @return {string}\n\t */\n\tgetDescription: function () {\n\t\treturn this.options.description;\n\t},\n\t/**\n\t * Return the page title for the thumbnail\n\t * @memberof Thumbnail\n\t * @instance\n\t * @return {string}\n\t */\n\tgetFileName: function () {\n\t\treturn this.options.filename;\n\t}\n} );\n\nmodule.exports = Thumbnail;\n","var browser = require( './Browser' ).getSingleton(),\n\tutil = require( './util' ),\n\tescapeHash = util.escapeHash,\n\tarrowOptions = {\n\t\tname: 'arrow',\n\t\tadditionalClassNames: 'indicator'\n\t},\n\tIcon = require( './Icon' );\n\n/**\n *\n * @typedef {Object} ToggledEvent\n * @prop {boolean} expanded True if section is opened, false if closed.\n * @prop {Page} page\n * @prop {boolean} isReferenceSection\n * @prop {JQuery.Object} $heading\n */\n\n/**\n * A class for enabling toggling\n *\n * @class Toggler\n * @param {Object} options\n * @param {OO.EventEmitter} options.eventBus Object used to emit section-toggled events.\n * @param {jQuery.Object} options.$container to apply toggling to\n * @param {string} options.prefix a prefix to use for the id.\n * @param {Page} options.page to allow storage of session for future visits\n * @param {Page} [options.isClosed]\n */\nfunction Toggler( options ) {\n\tthis.eventBus = options.eventBus;\n\tthis._enable( options.$container, options.prefix, options.page, options.isClosed );\n}\n\n/**\n * Using the settings module looks at what sections were previously expanded on\n * existing page.\n *\n * @param {Page} page\n * @return {Object} representing open sections\n */\nfunction getExpandedSections( page ) {\n\tvar expandedSections = JSON.parse( mw.storage.get( 'expandedSections' ) || '{}' );\n\texpandedSections[page.title] = expandedSections[page.title] || {};\n\treturn expandedSections;\n}\n\n/**\n* @param {Object} expandedSections\n* Save expandedSections to localStorage\n*/\nfunction saveExpandedSections( expandedSections ) {\n\tmw.storage.set(\n\t\t'expandedSections', JSON.stringify( expandedSections )\n\t);\n}\n\n/**\n * Given an expanded heading, store it to localStorage.\n * If the heading is collapsed, remove it from localStorage.\n *\n * @param {jQuery.Object} $heading - A heading belonging to a section\n * @param {Page} page\n */\nfunction storeSectionToggleState( $heading, page ) {\n\tvar headline = $heading.find( 'span' ).attr( 'id' ),\n\t\tisSectionOpen = $heading.hasClass( 'open-block' ),\n\t\texpandedSections = getExpandedSections( page );\n\n\tif ( headline ) {\n\t\tif ( isSectionOpen ) {\n\t\t\texpandedSections[page.title][headline] = ( new Date() ).getTime();\n\t\t} else {\n\t\t\tdelete expandedSections[page.title][headline];\n\t\t}\n\n\t\tsaveExpandedSections( expandedSections );\n\t}\n}\n\n/**\n * Expand sections that were previously expanded before leaving this page.\n * @param {Toggler} toggler\n * @param {jQuery.Object} $container\n * @param {Page} page\n */\nfunction expandStoredSections( toggler, $container, page ) {\n\tvar $sectionHeading, $headline,\n\t\texpandedSections = getExpandedSections( page ),\n\t\t$headlines = $container.find( '.section-heading span' );\n\n\t$headlines.each( function () {\n\t\t$headline = $container.find( this );\n\t\t$sectionHeading = $headline.parents( '.section-heading' );\n\t\t// toggle only if the section is not already expanded\n\t\tif (\n\t\t\texpandedSections[page.title][$headline.attr( 'id' )] &&\n\t\t!$sectionHeading.hasClass( 'open-block' )\n\t\t) {\n\t\t\ttoggler.toggle( $sectionHeading, page );\n\t\t}\n\t} );\n}\n\n/**\n * Clean obsolete (saved more than a day ago) expanded sections from\n * localStorage.\n * @param {Page} page\n */\nfunction cleanObsoleteStoredSections( page ) {\n\tvar now = ( new Date() ).getTime(),\n\t\texpandedSections = getExpandedSections( page ),\n\t\t// the number of days between now and the time a setting was saved\n\t\tdaysDifference;\n\tObject.keys( expandedSections ).forEach( function ( page ) {\n\t\tvar sections = expandedSections[ page ];\n\t\t// clean the setting if it is more than a day old\n\t\tObject.keys( sections ).forEach( function ( section ) {\n\t\t\tvar timestamp = sections[ section ];\n\t\t\tdaysDifference = Math.floor( ( now - timestamp ) / 1000 / 60 / 60 / 24 );\n\t\t\tif ( daysDifference >= 1 ) {\n\t\t\t\tdelete expandedSections[page][section];\n\t\t\t}\n\t\t} );\n\t} );\n\tsaveExpandedSections( expandedSections );\n}\n\n/**\n * Given a heading, toggle it and any of its children\n *\n * @memberof Toggler\n * @instance\n * @param {jQuery.Object} $heading A heading belonging to a section\n */\nToggler.prototype.toggle = function ( $heading ) {\n\tvar indicator,\n\t\twasExpanded = $heading.is( '.open-block' ),\n\t\tpage = $heading.data( 'page' ),\n\t\t$content = $heading.next();\n\n\t$heading.toggleClass( 'open-block' );\n\t$heading.data( 'indicator' ).remove();\n\n\tarrowOptions.rotation = wasExpanded ? 0 : 180;\n\tindicator = new Icon( arrowOptions ).prependTo( $heading );\n\t$heading.data( 'indicator', indicator );\n\n\t$content\n\t\t.toggleClass( 'open-block' )\n\t\t.attr( {\n\t\t\t'aria-pressed': !wasExpanded,\n\t\t\t'aria-expanded': !wasExpanded\n\t\t} );\n\n\t/**\n\t * Global event emitted after a section has been toggled\n\t * @event section-toggled\n\t * @type {ToggledEvent}\n\t */\n\tthis.eventBus.emit( 'section-toggled', {\n\t\texpanded: wasExpanded,\n\t\tpage: page,\n\t\tisReferenceSection: Boolean( $content.attr( 'data-is-reference-section' ) ),\n\t\t$heading: $heading\n\t} );\n\n\tif ( !browser.isWideScreen() ) {\n\t\tstoreSectionToggleState( $heading, page );\n\t}\n};\n\n/**\n * Enables toggling via enter and space keys\n *\n * @param {Toggler} toggler instance.\n * @param {jQuery.Object} $heading\n */\nfunction enableKeyboardActions( toggler, $heading ) {\n\t$heading.on( 'keypress', function ( ev ) {\n\t\tif ( ev.which === 13 || ev.which === 32 ) {\n\t\t\t// Only handle keypresses on the \"Enter\" or \"Space\" keys\n\t\t\ttoggler.toggle( $heading );\n\t\t}\n\t} ).find( 'a' ).on( 'keypress mouseup', function ( ev ) {\n\t\tev.stopPropagation();\n\t} );\n}\n\n/**\n * Reveals an element and its parent section as identified by it's id\n *\n * @memberof Toggler\n * @instance\n * @param {string} selector A css selector that identifies a single element\n * @param {Object} $container jQuery element to search in\n */\nToggler.prototype.reveal = function ( selector, $container ) {\n\tvar $target, $heading;\n\n\t// jQuery will throw for hashes containing certain characters which can break toggling\n\ttry {\n\t\t$target = $container.find( escapeHash( selector ) );\n\t\t$heading = $target.parents( '.collapsible-heading' );\n\t\t// The heading is not a section heading, check if in a content block!\n\t\tif ( !$heading.length ) {\n\t\t\t$heading = $target.parents( '.collapsible-block' ).prev( '.collapsible-heading' );\n\t\t}\n\t\tif ( $heading.length && !$heading.hasClass( 'open-block' ) ) {\n\t\t\tthis.toggle( $heading );\n\t\t}\n\t\tif ( $heading.length ) {\n\t\t\t// scroll again after opening section (opening section makes the page longer)\n\t\t\twindow.scrollTo( 0, $target.offset().top );\n\t\t}\n\t} catch ( e ) {}\n};\n\n/**\n * Enables section toggling in a given container when wgMFCollapseSectionsByDefault\n * is enabled.\n *\n * @memberof Toggler\n * @instance\n * @param {jQuery.Object} $container to apply toggling to\n * @param {string} prefix a prefix to use for the id.\n * @param {Page} page to allow storage of session for future visits\n * @param {Page} [isClosed] whether the element should begin closed\n * @private\n */\nToggler.prototype._enable = function ( $container, prefix, page, isClosed ) {\n\tvar tagName, expandSections, indicator, $content,\n\t\t$firstHeading,\n\t\t$link,\n\t\tself = this,\n\t\tcollapseSectionsByDefault = mw.config.get( 'wgMFCollapseSectionsByDefault' );\n\n\t// Also allow .section-heading if some extensions like Wikibase\n\t// want to toggle other headlines than direct descendants of $container.\n\t$firstHeading = $container.find( '> h1,> h2,> h3,> h4,> h5,> h6,.section-heading' ).eq( 0 );\n\ttagName = $firstHeading.prop( 'tagName' ) || 'H1';\n\n\tif ( collapseSectionsByDefault === undefined ) {\n\t\t// Old default behavior if on cached output\n\t\tcollapseSectionsByDefault = true;\n\t}\n\texpandSections = !collapseSectionsByDefault || mw.storage.get( 'expandSections' ) === 'true';\n\n\t$container.children( tagName ).each( function ( i ) {\n\t\tvar isReferenceSection,\n\t\t\t$heading = $container.find( this ),\n\t\t\t$indicator = $heading.find( '.indicator' ),\n\t\t\tid = prefix + 'collapsible-block-' + i;\n\t\t// Be sure there is a div wrapping the section content.\n\t\t// Otherwise, collapsible sections for this page is not enabled.\n\t\tif ( $heading.next().is( 'div' ) ) {\n\t\t\t$content = $heading.next( 'div' );\n\t\t\tisReferenceSection = Boolean( $content.attr( 'data-is-reference-section' ) );\n\t\t\t$heading\n\t\t\t\t.addClass( 'collapsible-heading ' )\n\t\t\t\t.data( 'section-number', i )\n\t\t\t\t.data( 'page', page )\n\t\t\t\t.attr( {\n\t\t\t\t\ttabindex: 0,\n\t\t\t\t\t'aria-haspopup': 'true',\n\t\t\t\t\t'aria-controls': id\n\t\t\t\t} )\n\t\t\t\t.on( 'click', function ( ev ) {\n\t\t\t\t\t// don't toggle, if the click target was a link\n\t\t\t\t\t// (a link in a section heading)\n\t\t\t\t\t// See T117880\n\t\t\t\t\tif ( !ev.target.href ) {\n\t\t\t\t\t\t// prevent taps/clicks on edit button after toggling (bug 56209)\n\t\t\t\t\t\tev.preventDefault();\n\t\t\t\t\t\tself.toggle( $heading );\n\t\t\t\t\t}\n\t\t\t\t} );\n\n\t\t\tarrowOptions.rotation = expandSections ? 180 : 0;\n\t\t\tindicator = new Icon( arrowOptions );\n\t\t\tif ( $indicator.length ) {\n\t\t\t\t// replace the existing indicator\n\t\t\t\t$indicator.replaceWith( indicator.$el );\n\t\t\t} else {\n\t\t\t\tindicator.prependTo( $heading );\n\t\t\t}\n\t\t\t$heading.data( 'indicator', indicator.$el );\n\t\t\t$content\n\t\t\t\t.addClass( 'collapsible-block' )\n\t\t\t\t.eq( 0 )\n\t\t\t\t.attr( {\n\t\t\t\t\t// We need to give each content block a unique id as that's\n\t\t\t\t\t// the only way we can tell screen readers what element we're\n\t\t\t\t\t// referring to (aria-controls)\n\t\t\t\t\tid: id,\n\t\t\t\t\t'aria-pressed': 'false',\n\t\t\t\t\t'aria-expanded': 'false'\n\t\t\t\t} );\n\n\t\t\tenableKeyboardActions( self, $heading );\n\t\t\tif (\n\t\t\t\t!isReferenceSection && (\n\t\t\t\t\t!isClosed && browser.isWideScreen() || expandSections\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\t// Expand sections by default on wide screen devices\n\t\t\t\t// or if the expand sections setting is set.\n\t\t\t\t// The wide screen logic for determining whether to collapse sections initially\n\t\t\t\t// should be kept in sync with mobileoptions#initLocalStorageElements().\n\t\t\t\tself.toggle( $heading );\n\t\t\t}\n\t\t}\n\t} );\n\n\t/* eslint-disable no-restricted-properties */\n\t/**\n\t * Checks the existing hash and toggles open any section that contains the fragment.\n\t *\n\t * @method\n\t */\n\tfunction checkHash() {\n\t\tvar hash = window.location.hash;\n\t\tif ( hash.indexOf( '#' ) === 0 ) {\n\t\t\tself.reveal( hash, $container );\n\t\t}\n\t}\n\n\t/**\n\t * Checks the value of wgInternalRedirectTargetUrl and reveals the collapsed\n\t * section that contains it if present\n\t *\n\t * @method\n\t */\n\tfunction checkInternalRedirectAndHash() {\n\t\tvar internalRedirect = mw.config.get( 'wgInternalRedirectTargetUrl' ),\n\t\t\tinternalRedirectHash = internalRedirect ? internalRedirect.split( '#' )[1] : false;\n\n\t\tif ( internalRedirectHash ) {\n\t\t\twindow.location.hash = internalRedirectHash;\n\t\t\tself.reveal( internalRedirectHash, $container );\n\t\t}\n\t}\n\t/* eslint-enable no-restricted-properties */\n\n\tcheckInternalRedirectAndHash();\n\tcheckHash();\n\t// Restricted to links created by editors and thus outside our control\n\t// T166544 - don't do this for reference links - they will be handled elsewhere\n\t$link = $container.find( 'a:not(.reference a)' );\n\t$link.on( 'click', function () {\n\t\t// the link might be an internal link with a hash.\n\t\t// if it is check if we need to reveal any sections.\n\t\tif ( $link.attr( 'href' ) !== undefined &&\n\t\t$link.attr( 'href' ).indexOf( '#' ) > -1\n\t\t) {\n\t\t\tcheckHash();\n\t\t}\n\t} );\n\tutil.getWindow().on( 'hashchange', function () {\n\t\tcheckHash();\n\t} );\n\n\tif ( !browser.isWideScreen() && page ) {\n\t\texpandStoredSections( this, $container, page );\n\t\tcleanObsoleteStoredSections( page );\n\t}\n};\n\nToggler._getExpandedSections = getExpandedSections;\nToggler._expandStoredSections = expandStoredSections;\nToggler._cleanObsoleteStoredSections = cleanObsoleteStoredSections;\n\nmodule.exports = Toggler;\n","/* global $, document */\nvar util = require( './util' ),\n\tmfExtend = require( './mfExtend' ),\n\t// Cached regex to split keys for `delegate`.\n\tdelegateEventSplitter = /^(\\S+)\\s*(.*)$/,\n\tidCounter = 0;\n\n/**\n * Generate a unique integer id (unique within the entire client session).\n * Useful for temporary DOM ids.\n * @param {string} prefix Prefix to be used when generating the id.\n * @return {string}\n */\nfunction uniqueId( prefix ) {\n\tvar id = ( ++idCounter ).toString();\n\treturn prefix ? prefix + id : id;\n}\n\n/**\n * Should be extended using extend().\n *\n * When options contains el property, this.$el in the constructed object\n * will be set to the corresponding jQuery object. Otherwise, this.$el\n * will be an empty div.\n *\n * When extended using extend(), if the extended prototype contains\n * template property, this.$el will be filled with rendered template (with\n * options parameter used as template data).\n *\n * template property can be a string which will be passed to mw.template.compile()\n * or an object that has a render() function which accepts an object with\n * template data as its argument (similarly to an object created by\n * mw.template.compile()).\n *\n * You can also define a defaults property which should be an object\n * containing default values for the template (if they're not present in\n * the options parameter).\n *\n * If this.$el is not a jQuery object bound to existing DOM element, the\n * view can be attached to an element using appendTo(), prependTo(),\n * insertBefore(), insertAfter() proxy functions.\n *\n * append(), prepend(), before(), after() can be used to modify $el. on()\n * can be used to bind events.\n *\n * You can also use declarative DOM events binding by specifying an `events`\n * map on the class. The keys will be 'event selector' and the value can be\n * either the name of a method to call, or a function. All methods and\n * functions will be executed on the context of the View.\n *\n * Inspired from Backbone.js\n * https://github.com/jashkenas/backbone/blob/master/backbone.js#L1128\n *\n * Example:\n * ```js\n *     var\n *       MyComponent = View.extend( {\n *         edit: function ( ev ) {\n *           //...\n *         },\n *         save: function ( ev ) {\n *           //...\n *         }\n *       } ),\n *       instance = new MyComponent({\n *         events: {\n *           'mousedown .title': 'edit',\n *           'click .button': 'save',\n *           'click .open': function(e) { ... }\n *         }\n *       });\n * ```\n *\n * Example:\n * ```js\n *     var View, section;\n *     function Section( options ) {\n *       var defaultOptions = {\n *         events: {\n *           // ...\n *         }\n *       }\n *       View.call( this, util.extends( {}, defaultOptions, options ) );\n *     }\n *     View = require( './View' );\n *     require( './mfExtend' )( Section, View, {\n *       template: mw.template.compile( \"&lt;h2&gt;{{title}}&lt;/h2&gt;\" ),\n *     } );\n *     section = new Section( { title: 'Test', text: 'Test section body' } );\n *     section.appendTo( 'body' );\n * ```\n *\n * @class View\n * @mixins OO.EventEmitter\n */\n\nfunction View() {\n\tthis.initialize.apply( this, arguments );\n}\nOO.mixinClass( View, OO.EventEmitter );\nmfExtend( View, {\n\t/**\n\t * Name of tag that contains the rendered template\n\t * @memberof View\n\t * @instance\n\t * @property {string} tagName\n\t */\n\ttagName: 'div',\n\t/**\n\t * Tells the View to ignore tagName and className when constructing the element\n\t * and to rely solely on the template\n\t * @memberof View\n\t * @instance\n\t * @property {boolean} isTemplateMode\n\t */\n\tisTemplateMode: false,\n\t/**\n\t * @memberof View\n\t * @instance\n\t * @property {Mixed}\n\t * Specifies the template used in render(). Object|string|HoganTemplate\n\t */\n\ttemplate: undefined,\n\n\t/**\n\t * Specifies partials (sub-templates) for the main template. Example:\n\t *\n\t *     @example\n\t *     // example content for the \"some\" template (sub-template will be\n\t *     // inserted where {{>content}} is):\n\t *     // <h1>Heading</h1>\n\t *     // {{>content}}\n\t *\n\t *     oo.mfExtend( SomeView, View, {\n\t *       template: M.template.get( 'some.hogan' ),\n\t *       templatePartials: { content: M.template.get( 'sub.hogan' ) }\n\t *     }\n\t *\n\t * @memberof View\n\t * @instance\n\t * @property {Object}\n\t */\n\ttemplatePartials: {},\n\n\t/**\n\t * A set of default options that are merged with options passed into the initialize\n\t * function.\n\t * @memberof View\n\t * @instance\n\t * @property {Object} defaults Default options hash.\n\t * @property {jQuery.Object|string} [defaults.el] jQuery selector to use for rendering.\n\t * @property {boolean} [defaults.skipTemplateRender] Whether to enhance views already in\n\t * DOM. When enabled, the template is disabled so that it is not rendered in the DOM.\n\t * Use in conjunction with View::defaults.$el to associate the View with an existing\n\t * already rendered element in the DOM.\n\t */\n\tdefaults: {},\n\n\t/**\n\t * Run once during construction to set up the View\n\t * @memberof View\n\t * @instance\n\t * @param {Object} options Object passed to the constructor.\n\t * @param {Object.<string, string>} [options.events]\n\t */\n\tinitialize: function ( options ) {\n\t\tvar self = this;\n\n\t\tOO.EventEmitter.call( this );\n\t\toptions = util.extend( {}, this.defaults, options );\n\t\tthis.options = options;\n\t\t// Assign a unique id for dom events binding/unbinding\n\t\tthis.cid = uniqueId( 'view' );\n\n\t\t// TODO: if template compilation is too slow, don't compile them on a\n\t\t// per object basis, but don't worry about it now (maybe add cache to\n\t\t// M.template.compile())\n\t\tif ( typeof this.template === 'string' ) {\n\t\t\tthis.template = mw.template.compile( this.template );\n\t\t}\n\n\t\tif ( options.el ) {\n\t\t\t// Note the element may not be in the document so must use global jQuery here\n\t\t\tthis.$el = $( options.el );\n\t\t} else {\n\t\t\tthis.$el = this.parseHTML( '<' + this.tagName + '>' );\n\t\t}\n\n\t\t// Make sure the element is ready to be manipulated\n\t\tif ( this.$el.length ) {\n\t\t\tthis._postInitialize( options );\n\t\t} else {\n\t\t\tutil.docReady( function () {\n\t\t\t\t// Note the element may not be in the document so must use global jQuery here\n\t\t\t\tself.$el = $( options.el );\n\t\t\t\tself._postInitialize( options );\n\t\t\t} );\n\t\t}\n\t},\n\n\t/**\n\t * Called when this.$el is ready.\n\t * @memberof View\n\t * @instance\n\t * @private\n\t * @param {Object} props\n\t */\n\t_postInitialize: function ( props ) {\n\t\tvar\n\t\t\tBORDER_BOX_CLASS = 'view-border-box',\n\t\t\tclassName = props.className;\n\n\t\tthis.$el.addClass( className );\n\t\t// border-box will be added provided this flag is not set\n\t\tif ( props.isBorderBox !== false ) {\n\t\t\tthis.$el.addClass( BORDER_BOX_CLASS );\n\t\t}\n\n\t\tthis.render( {} );\n\t},\n\n\t/**\n\t * Function called before the view is rendered. Can be redefined in\n\t * objects that extend View.\n\t * @memberof View\n\t * @instance\n\t */\n\tpreRender: function () {},\n\n\t/**\n\t * Function called after the view is rendered. Can be redefined in\n\t * objects that extend View.\n\t *\n\t * @memberof View\n\t * @instance\n\t */\n\tpostRender: function () {},\n\n\t// eslint-disable-next-line valid-jsdoc\n\t/**\n\t * Fill this.$el with template rendered using data if template is set.\n\t *\n\t * @memberof View\n\t * @instance\n\t * @param {Object} data Template data. Will be merged into the view's\n\t * options\n\t * @chainable\n\t */\n\trender: function ( data ) {\n\t\tvar $el, html;\n\t\tutil.extend( this.options, data );\n\t\tthis.preRender();\n\t\tthis.undelegateEvents();\n\t\tif ( this.template && !this.options.skipTemplateRender ) {\n\t\t\thtml = this.template.render( this.options, this.templatePartials );\n\t\t\tif ( this.isTemplateMode ) {\n\t\t\t\t$el = $( html );\n\t\t\t\tthis.$el.replaceWith( $el );\n\t\t\t\tthis.$el = $el;\n\t\t\t} else {\n\t\t\t\tthis.$el.html( html );\n\t\t\t}\n\t\t}\n\t\tthis.postRender();\n\t\tthis.delegateEvents();\n\t\treturn this;\n\t},\n\n\t/**\n\t * Wraps this.$el.find, so that you can search for elements in the view's\n\t * ($el's) scope.\n\t *\n\t * @memberof View\n\t * @instance\n\t * @param {string} query A jQuery CSS selector.\n\t * @return {JQuery.Object} jQuery object containing results of the search.\n\t */\n\t$: function ( query ) {\n\t\tmw.log.warn( 'Use of View.$ is deprecated. Use View.$el.find instead.' );\n\t\treturn this.$el.find( query );\n\t},\n\n\t/**\n\t * Set callbacks, where `this.options.events` is a hash of\n\t *\n\t * { 'event selector': 'callback' }\n\t *\n\t * {\n\t *   'mousedown .title': 'edit',\n\t *   'click .button': 'save',\n\t *   'click .open': function(e) { ... }\n\t * }\n\t *\n\t * pairs. Callbacks will be bound to the view, with `this` set properly.\n\t * Uses event delegation for efficiency.\n\t * Omitting the selector binds the event to `this.el`.\n\t *\n\t * @memberof View\n\t * @instance\n\t * @param {Object} events Optionally set this events instead of the ones on this.\n\t */\n\tdelegateEvents: function ( events ) {\n\t\tvar match, key, method;\n\t\tevents = events || this.options.events;\n\t\tif ( events ) {\n\t\t\t// Remove current events before re-binding them\n\t\t\tthis.undelegateEvents();\n\t\t\tfor ( key in events ) {\n\t\t\t\tmethod = events[ key ];\n\t\t\t\t// If the method is a string name of this.method, get it\n\t\t\t\tif ( typeof method !== 'function' ) {\n\t\t\t\t\tmethod = this[ events[ key ] ];\n\t\t\t\t}\n\t\t\t\tif ( method ) {\n\t\t\t\t\t// Extract event and selector from the key\n\t\t\t\t\tmatch = key.match( delegateEventSplitter );\n\t\t\t\t\tthis.delegate( match[ 1 ], match[ 2 ], method.bind( this ) );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t/**\n\t * Add a single event listener to the view's element (or a child element\n\t * using `selector`). This only works for delegate-able events: not `focus`,\n\t * `blur`, and not `change`, `submit`, and `reset` in Internet Explorer.\n\t *\n\t * @memberof View\n\t * @instance\n\t * @param {string} eventName\n\t * @param {string} selector\n\t * @param {Function} listener\n\t */\n\tdelegate: function ( eventName, selector, listener ) {\n\t\tthis.$el.on( eventName + '.delegateEvents' + this.cid, selector,\n\t\t\tlistener );\n\t},\n\n\t/**\n\t * Clears all callbacks previously bound to the view by `delegateEvents`.\n\t * You usually don't need to use this, but may wish to if you have multiple\n\t * views attached to the same DOM element.\n\t * @memberof View\n\t * @instance\n\t */\n\tundelegateEvents: function () {\n\t\tif ( this.$el ) {\n\t\t\tthis.$el.off( '.delegateEvents' + this.cid );\n\t\t}\n\t},\n\n\t/**\n\t * A finer-grained `undelegateEvents` for removing a single delegated event.\n\t * `selector` and `listener` are both optional.\n\t *\n\t * @memberof View\n\t * @instance\n\t * @param {string} eventName\n\t * @param {string} selector\n\t * @param {Function} listener\n\t */\n\tundelegate: function ( eventName, selector, listener ) {\n\t\tthis.$el.off( eventName + '.delegateEvents' + this.cid, selector,\n\t\t\tlistener );\n\t},\n\n\t/**\n\t * See parseHTML method of util singleton\n\t *\n\t * @memberof View\n\t * @instance\n\t * @param {string} html to turn into a jQuery object.\n\t * @return {jQuery.Object}\n\t */\n\tparseHTML: function ( html ) {\n\t\t// document is explicitly passed due to a bug we found in Safari 11.1.2 where failure\n\t\t// to use document resulted in an element without access to the documentElement\n\t\t// this should be redundant, but no problem in being explicit (T214451).\n\t\treturn util.parseHTML( html, document );\n\t}\n} );\n\n/**\n * @memberof View\n * @instance\n * @func append\n * @param {...(string|Node|Node[]|JQuery)} contents\n * @return {this}\n */\n\n/**\n * @memberof View\n * @instance\n * @func append\n * @param {function(number, string): string|Node|Node[]|JQuery} contents\n * @return {this}\n */\n\n/**\n * @memberof View\n * @instance\n * @func prepend\n * @param {...(string|Node|Node[]|JQuery)} contents\n * @return {this}\n */\n\n/**\n * @memberof View\n * @instance\n * @func prepend\n * @param {function(number, string): string|Node|Node[]|JQuery} contents\n * @return {this}\n */\n\n/**\n * @memberof View\n * @instance\n * @func appendTo\n * @param {string|Node|Node[]|JQuery} target\n * @return {this}\n */\n\n/**\n * @memberof View\n * @instance\n * @func prependTo\n * @param {string|Node|Node[]|JQuery} target\n * @return {this}\n */\n\n/**\n * @memberof View\n * @instance\n * @func after\n * @param {...(string|Node|Node[]|JQuery)} contents\n * @return {this}\n */\n\n/**\n * @memberof View\n * @instance\n * @func after\n * @param {function(number, string): string|Node|Node[]|JQuery} contents\n * @return {this}\n */\n\n/**\n * @memberof View\n * @instance\n * @func before\n * @param {...(string|Node|Node[]|JQuery)} contents\n * @return {this}\n */\n\n/**\n * @memberof View\n * @instance\n * @func before\n * @param {function(number, string): string|Node|Node[]|JQuery} contents\n * @return {this}\n */\n\n/**\n * @memberof View\n * @instance\n * @property {jQuery.Object} $el\n */\n\n/**\n * @memberof View\n * @instance\n * @func insertAfter\n * @param {string|Node|Node[]|JQuery} target\n * @return {this}\n */\n\n/**\n * @memberof View\n * @instance\n * @func insertBefore\n * @param {string|Node|Node[]|JQuery} target\n * @return {this}\n */\n\n/**\n * @memberof View\n * @instance\n * @func remove\n * @param {string} [selector]\n * @return {this}\n */\n\n/**\n * @memberof View\n * @instance\n * @func detach\n * @param {string} [selector]\n * @return {this}\n */\n\n[\n\t'append',\n\t'prepend',\n\t'appendTo',\n\t'prependTo',\n\t'after',\n\t'before',\n\t'insertAfter',\n\t'insertBefore',\n\t'remove',\n\t'detach'\n].forEach( function ( prop ) {\n\tView.prototype[prop] = function () {\n\t\tthis.$el[prop].apply( this.$el, arguments );\n\t\treturn this;\n\t};\n} );\n\n/**\n * Generates a view with children\n *\n * @param {Object} options\n * @param {jQuery.Element[]} children\n * @return {View}\n */\nView.make = function ( options, children ) {\n\tvar view = new View( options );\n\tchildren.forEach( function ( $child ) {\n\t\tview.append( $child );\n\t} );\n\treturn view;\n};\n\nmodule.exports = View;\n","var util = require( './util' ),\n\tdefaultParams = {\n\t\taction: 'query',\n\t\tformatversion: 2\n\t};\n\n/**\n * Extends the default params for an action query with otherParams\n * @param {Object} otherParams\n * @return {Object}\n */\nfunction actionParams( otherParams ) {\n\tvar scriptPath = mw.config.get( 'wgMFContentProviderScriptPath' );\n\treturn util.extend( {}, defaultParams, {\n\t\torigin: scriptPath ? '*' : undefined\n\t}, otherParams );\n}\n\nmodule.exports = actionParams;\n","/* This module defines several types of cache classes to use in other\n * modules.\n * The interface, that all types use, is kept synchronous driven by current\n * usage patterns, but will need to be revisited in case usage patterns\n * suggest we need asynchronous caches.\n */\n\n/**\n * In memory cache implementation\n *\n * @class MemoryCache\n */\nfunction MemoryCache() {\n\tthis._cache = {};\n}\n\n/**\n * Retrieve a cached value from a key\n * @memberof MemoryCache\n * @instance\n * @param {string} key\n * @return {Mixed}\n */\nMemoryCache.prototype.get = function ( key ) {\n\treturn this._cache[ key ];\n};\n\n/**\n * Cache a value by key\n * @memberof MemoryCache\n * @instance\n * @param {string} key\n * @param {Mixed} value\n */\nMemoryCache.prototype.set = function ( key, value ) {\n\tthis._cache[ key ] = value;\n};\n\n/**\n * Null object cache implementation\n *\n * @class NoCache\n */\nfunction NoCache() { }\n\n/**\n * NoOp\n * @memberof NoCache\n * @instance\n */\nNoCache.prototype.get = function () { };\n\n/**\n * NoOp\n * @memberof NoCache\n * @instance\n */\nNoCache.prototype.set = function () { };\n\nmodule.exports = {\n\tMemoryCache: MemoryCache,\n\tNoCache: NoCache\n};\n","/**\n * Mobile mode helper class\n *\n * @class context\n * @singleton\n */\nmodule.exports = {\n\t/**\n\t * Gets current mobile mode\n\t * @memberof context\n\t * @instance\n\t * @return {string|null} Name of mode - either `stable` or `beta`. It is `null` if desktop.\n\t */\n\tgetMode: function () {\n\t\treturn mw.config.get( 'wgMFMode' );\n\t}\n};\n","var util = require( './util' ),\n\tactionParams = require( './actionParams.js' );\n\n/**\n * Extends the API query parameters to include those parameters required to also fetch Wikibase\n * descriptions and appropriately sized thumbnail images as well as those required to make a query.\n *\n * This function wraps `util.extend` with some Wikibase-specific configuration\n * variable management\n * but, like `util.extend`, is variadic and so can be used as a replacement for it in search\n * gateways, e.g.\n *\n * ```\n * var params = extendSearchParams(\n *   'nearby',\n *   baseParams,\n *   specializedParams,\n *   moreSpecializedParams\n * );\n * ```\n *\n * @param {string} feature The name of the feature\n * @throws {Error} If `feature` isn't one that shows Wikidata descriptions. See the\n *  `wgMFDisplayWikibaseDescriptions` configuration variable for detail\n * @return {Object}\n */\nfunction extendSearchParams( feature ) {\n\tvar displayWikibaseDescriptions = mw.config.get( 'wgMFDisplayWikibaseDescriptions', {} ),\n\t\tscriptPath = mw.config.get( 'wgMFContentProviderScriptPath' ),\n\t\targs,\n\t\tresult;\n\n\tif ( !Object.prototype.hasOwnProperty.call( displayWikibaseDescriptions, feature ) ) {\n\t\tthrow new Error( '\"' + feature + '\" isn\\'t a feature that shows Wikibase descriptions.' );\n\t}\n\n\t// Construct the arguments for a call to `util.extend`\n\t// such that if it were hand-written, then it\n\t// would look like the following:\n\t//\n\t// ```\n\t// var result = util.extend( {\n\t//   prop: []\n\t// }, params, /* ..., */ mw.config.get( 'wgMFSearchAPIParams' ) );\n\t// ```\n\targs = Array.prototype.slice.call( arguments, 1 );\n\targs.unshift( {\n\t\tprop: []\n\t} );\n\targs.push( mw.config.get( 'wgMFSearchAPIParams' ) );\n\n\tresult = util.extend.apply( {}, args );\n\tresult.prop = result.prop.concat( mw.config.get( 'wgMFQueryPropModules' ) );\n\n\tif ( displayWikibaseDescriptions[feature] ) {\n\t\tif ( result.prop.indexOf( 'description' ) === -1 ) {\n\t\t\tresult.prop.push( 'description' );\n\t\t}\n\t}\n\n\tif ( scriptPath ) {\n\t\t// A foreign api is being accessed! Enable anonymous CORS queries!\n\t\tresult.origin = '*';\n\t}\n\treturn actionParams( result );\n}\nmodule.exports = extendSearchParams;\n","var\n\tCANCEL_GLYPH = 'overlay-close',\n\tIcon = require( './Icon' ),\n\tutil = require( './util' );\n\n/**\n * A set of shared icons.\n *\n * Factory methods are used to keep separate features that use the same icons\n * from accidentally manipulating one another's DOM when calling methods like\n * `remove`.\n *\n * @class icons\n * @singleton\n * @uses Icon\n */\nmodule.exports = {\n\tCANCEL_GLYPH: CANCEL_GLYPH,\n\t// Exported to support testing and stubbing\n\tIcon: Icon,\n\t/**\n\t * Gets a cancel icon\n\t *\n\t * The icon should be used to inform the user that the front-end is\n\t * communicating with the back-end.\n\t * @memberof icons\n\t * @instance\n\t * @param {string} variant\n\t * @return {Icon}\n\t */\n\tcancel: function ( variant ) {\n\t\tvar glyph = variant ? CANCEL_GLYPH + '-' + variant : CANCEL_GLYPH;\n\t\treturn new this.Icon( {\n\t\t\ttagName: 'button',\n\t\t\tname: glyph,\n\t\t\tadditionalClassNames: 'cancel',\n\t\t\tlabel: mw.msg( 'mobile-frontend-overlay-close' )\n\t\t} );\n\t},\n\t/**\n\t * Gets a spinner icon.\n\t *\n\t * The icon should be used to inform the user that the front-end is\n\t * communicating with the back-end.\n\t * @memberof icons\n\t * @instance\n\t * @param {Object} [options] See `Icon` for more details\n\t * @return {Icon}\n\t */\n\tspinner: function ( options ) {\n\t\toptions = options || {};\n\n\t\treturn new this.Icon( util.extend( options, {\n\t\t\tname: 'spinner',\n\t\t\tlabel: mw.msg( 'mobile-frontend-loading-message' ),\n\t\t\tadditionalClassNames: 'spinner loading'\n\t\t} ) );\n\t},\n\t/**\n\t * Gets a non-filled watch star icon.\n\t *\n\t * @memberof icons\n\t * @instance\n\t * @return {Icon}\n\t */\n\twatchIcon: function () {\n\t\treturn new this.Icon( {\n\t\t\tname: 'watch',\n\t\t\tadditionalClassNames: 'watch-this-article'\n\t\t} );\n\t},\n\t/**\n\t * Gets a filled watch star icon.\n\t *\n\t * @memberof icons\n\t * @instance\n\t * @return {Icon}\n\t */\n\twatchedIcon: function () {\n\t\treturn new this.Icon( {\n\t\t\tname: 'watched',\n\t\t\tadditionalClassNames: 'watch-this-article watched'\n\t\t} );\n\t}\n};\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 {PageGateway} gateway\n * @return {jQuery.Promise} Resolves to LanguageSearcher\n */\nfunction loadLanguageSearcher( gateway ) {\n\treturn mw.loader.using( 'mobile.languages.structured' ).then( function () {\n\t\treturn gateway.getPageLanguages( mw.config.get( 'wgPageName' ), mw.config.get( 'wgUserLanguage' ) );\n\t} ).then( function ( 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\tdeviceLanguage: getDeviceLanguage( navigator )\n\t\t} );\n\n\t} );\n}\n\n/**\n * Factory function that returns a language featured instance of an Overlay\n *\n * @param {PageGateway} pageGateway\n * @return {Overlay}\n */\nfunction languageOverlay( pageGateway ) {\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( pageGateway ) )\n\t);\n}\n\n// To make knowing when async logic has resolved easier in tests\nlanguageOverlay.test = {\n\tloadLanguageSearcher: loadLanguageSearcher\n};\n\nmodule.exports = languageOverlay;\n","var\n\tutil = require( '../util' ),\n\tplaceholderClass = 'lazy-image-placeholder';\n\n/**\n * @param {HTMLElement} root\n * @return {HTMLElement[]}\n */\nfunction queryPlaceholders( root ) {\n\treturn Array.prototype.slice.call(\n\t\troot.getElementsByClassName( placeholderClass )\n\t);\n}\n\n/**\n * Load an image on demand\n * @param {HTMLElement[]} placeholders a list of images that have not been loaded.\n * @return {JQuery.Deferred}\n */\nfunction loadImages( placeholders ) {\n\treturn util.Promise.all(\n\t\tplaceholders.map( function ( placeholder ) {\n\t\t\treturn module.exports.loadImage( placeholder ).promise;\n\t\t} )\n\t);\n}\n\n/**\n * Load an image on demand\n * @param {HTMLElement} placeholder\n * @return {{promise: JQuery.Deferred<'load'|'error'>, image: HTMLImageElement}}\n */\nfunction loadImage( placeholder ) {\n\tvar\n\t\tdeferred = util.Deferred(),\n\t\t// data-width and height are attributes and do not specify dimension.\n\t\twidth = placeholder.dataset.width || '0',\n\t\theight = placeholder.dataset.height || '0',\n\t\timage = new Image( parseInt( width, 10 ), parseInt( height, 10 ) );\n\n\timage.className = placeholder.dataset.class || '';\n\timage.alt = placeholder.dataset.alt || '';\n\timage.style.cssText = placeholder.style.cssText || '';\n\n\t// When the image has loaded\n\timage.addEventListener( 'load', function () {\n\t\t// Swap the HTML inside the placeholder (to keep the layout and\n\t\t// dimensions the same and not trigger layouts\n\t\timage.classList.add( 'image-lazy-loaded' );\n\t\tif ( placeholder.parentNode ) {\n\t\t\tplaceholder.parentNode.replaceChild( image, placeholder );\n\t\t}\n\t\tdeferred.resolve( 'load' );\n\t}, { once: true } );\n\timage.addEventListener( 'error', function () {\n\t\t// Never reject. Quietly resolve so that jQuery.when() awaits for all Deferreds to complete.\n\t\t// Reevaluate using Deferred.reject in T136693.\n\t\tdeferred.resolve( 'error' );\n\t}, { once: true } );\n\n\t// Trigger image download after binding the load handler\n\timage.src = placeholder.dataset.src || '';\n\timage.srcset = placeholder.dataset.srcset || '';\n\n\treturn {\n\t\tpromise: deferred,\n\t\timage: image\n\t};\n}\n\nmodule.exports = {\n\tqueryPlaceholders: queryPlaceholders,\n\tloadImages: loadImages,\n\tloadImage: loadImage,\n\ttest: {\n\t\tplaceholderClass: placeholderClass\n\t}\n};\n","var\n\tlazyImageLoader = require( './lazyImages/lazyImageLoader' ),\n\tutil = require( './util' ),\n\tPage = require( './Page' ),\n\tDeferred = util.Deferred,\n\ticons = require( './icons' ),\n\tspinner = icons.spinner();\n\n/**\n * Load the references section content from API if it's not already loaded.\n *\n * All references tags content will be loaded per section.\n * @param {OO.EventEmitter} eventBus\n * @param {ToggledEvent} data Information about the section.\n * @param {ReferencesGateway} gateway\n * @param {Page} page\n * @return {jQuery.Promise|void} rejected when not a reference section.\n */\nfunction loadReferences( eventBus, data, gateway, page ) {\n\tvar $content, $spinner;\n\n\t// If the section was expanded before toggling, do not load anything as\n\t// section is being collapsed now.\n\t// Also return early if lazy loading is not required or the section is\n\t// not a reference section\n\tif (\n\t\tdata.expanded ||\n\t\t!data.isReferenceSection\n\t) {\n\t\treturn;\n\t}\n\n\t$content = data.$heading.next();\n\n\tfunction loadImagesAndSetData() {\n\t\t// lazy load images if any\n\t\tlazyImageLoader.loadImages( lazyImageLoader.queryPlaceholders( $content[0] ) );\n\t\t// Do not attempt further loading even if we're unable to load this time.\n\t\t$content.data( 'are-references-loaded', 1 );\n\t}\n\n\tif ( !$content.data( 'are-references-loaded' ) ) {\n\t\t$content.children().addClass( 'hidden' );\n\t\t$spinner = spinner.$el.prependTo( $content );\n\n\t\t// First ensure we retrieve all of the possible lists\n\t\treturn gateway.getReferencesLists( data.page )\n\t\t\t.then( function () {\n\t\t\t\tvar lastId;\n\n\t\t\t\t$content.find( '.mf-lazy-references-placeholder' ).each( function () {\n\t\t\t\t\tvar refListIndex = 0,\n\t\t\t\t\t\t$placeholder = $content.find( this ),\n\t\t\t\t\t\t// search for id of the collapsible heading\n\t\t\t\t\t\tid = getSectionId( $placeholder );\n\n\t\t\t\t\tif ( lastId !== id ) {\n\t\t\t\t\t\t// If the placeholder belongs to a new section reset index\n\t\t\t\t\t\trefListIndex = 0;\n\t\t\t\t\t\tlastId = id;\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// otherwise increment it\n\t\t\t\t\t\trefListIndex++;\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( id ) {\n\t\t\t\t\t\tgateway.getReferencesList( data.page, id )\n\t\t\t\t\t\t\t.then( function ( refListElements ) {\n\t\t\t\t\t\t\t\t// Note if no section html is provided\n\t\t\t\t\t\t\t\t// no substitution will happen\n\t\t\t\t\t\t\t\t// so user is forced to rely on placeholder link.\n\t\t\t\t\t\t\t\tif ( refListElements && refListElements[refListIndex] ) {\n\t\t\t\t\t\t\t\t\t$placeholder.replaceWith(\n\t\t\t\t\t\t\t\t\t\trefListElements[refListIndex]\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t\t// Show the section now the references lists have been placed.\n\t\t\t\t$spinner.remove();\n\t\t\t\t$content.children().removeClass( 'hidden' );\n\t\t\t\t/**\n\t\t\t\t * Fired when references list is loaded into the HTML\n\t\t\t\t * @event references-loaded\n\t\t\t\t */\n\t\t\t\teventBus.emit( 'references-loaded', page );\n\n\t\t\t\tloadImagesAndSetData();\n\t\t\t}, function () {\n\t\t\t\t$spinner.remove();\n\t\t\t\t// unhide on a failure\n\t\t\t\t$content.children().removeClass( 'hidden' );\n\n\t\t\t\tloadImagesAndSetData();\n\t\t\t} );\n\t} else {\n\t\treturn Deferred().reject().promise();\n\t}\n}\n\n/**\n * Get the id of the section $el belongs to.\n * @param {jQuery.Object} $el\n * @return {string|null} either the anchor (id attribute of the section heading\n *  or null if none found)\n */\nfunction getSectionId( $el ) {\n\tvar id,\n\t\thSelector = Page.HEADING_SELECTOR,\n\t\t$parent = $el.parent(),\n\t\t// e.g. matches Subheading in\n\t\t// <h2>H</h2><div><h3 id=\"subheading\">Subh</h3><a class=\"element\"></a></div>\n\t\t$heading = $el.prevAll( hSelector ).eq( 0 );\n\n\tif ( $heading.length ) {\n\t\tid = $heading.find( '.mw-headline' ).attr( 'id' );\n\t\tif ( id ) {\n\t\t\treturn id;\n\t\t}\n\t}\n\tif ( $parent.length ) {\n\t\t// if we couldnt find a sibling heading, check the sibling of the parents\n\t\t// consider <div><h2 /><div><$el/></div></div>\n\t\treturn getSectionId( $parent );\n\t} else {\n\t\treturn null;\n\t}\n}\n\nmodule.exports = {\n\tloadReferences: loadReferences,\n\ttest: {\n\t\tgetSectionId: getSectionId\n\t}\n};\n","var\n\ticons = require( './icons' ),\n\tOverlay = require( './Overlay' );\n\n/**\n * Overlay that initially shows loading animation until\n * caller hides it with .hide()\n *\n * @return {Overlay}\n */\nfunction loadingOverlay() {\n\tvar overlay = new Overlay( {\n\t\tclassName: 'overlay overlay-loading',\n\t\tnoHeader: true\n\t} );\n\ticons.spinner().$el.appendTo( overlay.$el.find( '.overlay-content' ) );\n\treturn overlay;\n}\n\nmodule.exports = loadingOverlay;\n","/**\n * Extends a class with new methods and member properties.\n *\n * @param {Function} Child function\n * @param {Object|Function} ParentOrPrototype class to inherit from\n *  OR if no inheriting class a prototype to extend the class with\n * @param {Object} [prototype]\n */\nfunction mfExtend( Child, ParentOrPrototype, prototype ) {\n\tvar key;\n\tif ( prototype ) {\n\t\tOO.inheritClass( Child, ParentOrPrototype );\n\t} else {\n\t\tOO.initClass( Child );\n\t\tprototype = ParentOrPrototype;\n\t}\n\tfor ( key in prototype ) {\n\t\tChild.prototype[key] = prototype[key];\n\t}\n}\n\nmodule.exports = mfExtend;\n","/**\n * Class for managing modules\n *\n * A module in this context is essentially a Javascript class (not to be confused with\n * ResourceLoader modules).\n *\n * @class ModuleLoader\n */\nfunction ModuleLoader() {\n\t/**\n\t * @property {Object} register of defined modules\n\t * @private\n\t */\n\tthis._register = {};\n}\n\nModuleLoader.prototype = {\n\t/**\n\t * Require (import) a module previously defined using define().\n\t * Searches core module registry using mw.loader.require before consulting\n\t * its own local registry. This method is deprecated, please do not use.\n\t * @memberof ModuleLoader\n\t * @instance\n\t * @param {string} id Required module id.\n\t * @return {Object} Required module, can be any JavaScript object.\n\t */\n\trequire: function ( id ) {\n\t\tvar module, args,\n\t\t\tregistry = this._register;\n\n\t\t/**\n\t\t * @return {Object} Module\n\t\t */\n\t\tfunction localRequire() {\n\t\t\tif ( !Object.hasOwnProperty.call( registry, id ) ) {\n\t\t\t\tthrow new Error( 'MobileFrontend Module not found: ' + id );\n\t\t\t}\n\t\t\treturn registry[ id ];\n\t\t}\n\t\targs = id.split( '/' );\n\t\ttry {\n\t\t\tmodule = mw.loader.require( args[0] );\n\t\t\tif ( module[ args[1] ] ) {\n\t\t\t\treturn module[ args[1] ];\n\t\t\t} else {\n\t\t\t\treturn localRequire();\n\t\t\t}\n\t\t} catch ( e ) {\n\t\t\treturn localRequire();\n\t\t}\n\t},\n\n\t/**\n\t * Define a module which can be later required (imported) using require().\n\t * @memberof ModuleLoader\n\t * @instance\n\t * @param {string} id Defined module id.\n\t * @param {Object} obj Defined module body, can be any JavaScript object.\n\t * @return {Object}\n\t */\n\tdefine: function ( id, obj ) {\n\t\tvar self = this;\n\n\t\tif ( Object.hasOwnProperty.call( this._register, id ) ) {\n\t\t\tthrow new Error( 'Module already exists: ' + id );\n\t\t}\n\t\tthis._register[ id ] = obj;\n\t\t// return an object of additionally functions to do with the registered module\n\t\treturn {\n\t\t\t/**\n\t\t\t * @see ModuleLoader#deprecate\n\t\t\t * @param {string} deprecatedId Defined module id, which is deprecated.\n\t\t\t * @ignore\n\t\t\t */\n\t\t\tdeprecate: function ( deprecatedId ) {\n\t\t\t\tself.deprecate( deprecatedId, obj, id );\n\t\t\t}\n\t\t};\n\t},\n\n\t/**\n\t * Deprecate a module and give an replacement (if there is any).\n\t * @memberof ModuleLoader\n\t * @instance\n\t * @param {string} id Defined module id, which is deprecated.\n\t * @param {Object} obj Defined module body, can be any JavaScript object.\n\t * @param {string} [replacement] Give an optional replacement for this module (which\n\t * needs to be already defined!)\n\t */\n\tdeprecate: function ( id, obj, replacement ) {\n\t\tvar msg;\n\t\tif ( replacement ) {\n\t\t\t// add an alternative for this module, if any given\n\t\t\tmsg = 'Use ' + replacement + ' instead.';\n\t\t}\n\t\t// register it as a deprecated one\n\t\tmw.log.deprecate( this._register, id, obj, msg );\n\t}\n};\n\nmodule.exports = ModuleLoader;\n","var ModuleLoader = require( './moduleLoader' );\n\nmodule.exports = new ModuleLoader();\n","var\n\ticons = require( './icons' ),\n\tView = require( './View' );\n\n/**\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 * @param {jQuery.Promise} promise\n * @return {View}\n */\nfunction promisedView( promise ) {\n\tvar view = new View( {\n\t\tclassName: 'promised-view'\n\t} );\n\tview.$el.append( icons.spinner().$el );\n\tpromise.then( function ( newView ) {\n\t\tview.$el.replaceWith( newView.$el );\n\t\t// update the internal reference.\n\t\tview.$el = newView.$el;\n\t}, function ( 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\nmodule.exports = promisedView;\n","var Drawer = require( './../Drawer' ),\n\tutil = require( './../util' ),\n\ticons = require( './../icons' ),\n\tmfExtend = require( './../mfExtend' ),\n\tReferencesGateway = require( './ReferencesGateway' ),\n\tIcon = require( './../Icon' );\n\n/**\n * Drawer for references\n * @class ReferencesDrawer\n * @extends Drawer\n * @uses Icon\n * @param {Object} props\n */\nfunction ReferencesDrawer( props ) {\n\tDrawer.call(\n\t\tthis,\n\t\tutil.extend(\n\t\t\t{\n\t\t\t\tclassName: 'drawer position-fixed text references',\n\t\t\t\tevents: { 'click sup a': 'showNestedReference' }\n\t\t\t},\n\t\t\tprops\n\t\t)\n\t);\n}\n\nmfExtend( ReferencesDrawer, Drawer, {\n\t/**\n\t * @memberof ReferencesDrawer\n\t * @instance\n\t * @mixes Drawer#defaults\n\t * @property {Object} defaults Default options hash.\n\t * @property {string} defaults.cancelButton HTML of the button that closes the drawer.\n\t * @property {boolean} defaults.error whether an error message is being shown\n\t */\n\tdefaults: util.extend( {}, Drawer.prototype.defaults, {\n\t\tspinner: icons.spinner().toHtmlString(),\n\t\tcancelButton: icons.cancel( 'gray' ).toHtmlString(),\n\t\tcitation: new Icon( {\n\t\t\tisSmall: true,\n\t\t\tname: 'citation',\n\t\t\tadditionalClassNames: 'text',\n\t\t\thasText: true,\n\t\t\tlabel: mw.msg( 'mobile-frontend-references-citation' )\n\t\t} ).toHtmlString(),\n\t\terrorClassName: new Icon( {\n\t\t\tname: 'error',\n\t\t\thasText: true,\n\t\t\tisSmall: true\n\t\t} ).getClassName()\n\t} ),\n\t/**\n\t * @inheritdoc\n\t * @memberof ReferencesDrawer\n\t * @instance\n\t */\n\tshow: function () {\n\t\treturn Drawer.prototype.show.apply( this, arguments );\n\t},\n\t/**\n\t * @memberof ReferencesDrawer\n\t * @instance\n\t */\n\ttemplate: mw.template.get( 'mobile.startup', 'ReferencesDrawer.hogan' ),\n\t/**\n\t * @inheritdoc\n\t * @memberof ReferencesDrawer\n\t * @instance\n\t */\n\tcloseOnScroll: false,\n\t/**\n\t * @inheritdoc\n\t * @memberof ReferencesDrawer\n\t * @instance\n\t */\n\tpostRender: function () {\n\t\tvar windowHeight = util.getWindow().height();\n\n\t\tDrawer.prototype.postRender.apply( this );\n\n\t\t// make sure the drawer doesn't take up more than 50% of the viewport height\n\t\tif ( windowHeight / 2 < 400 ) {\n\t\t\tthis.$el.css( 'max-height', windowHeight / 2 );\n\t\t}\n\n\t\tthis.on( 'show', this.onShow.bind( this ) );\n\t\tthis.on( 'hide', this.onHide.bind( this ) );\n\t},\n\t/**\n\t * Make body not scrollable\n\t * @memberof ReferencesDrawer\n\t * @instance\n\t */\n\tonShow: function () {\n\t\tutil.getDocument().find( 'body' ).addClass( 'drawer-enabled' );\n\t},\n\t/**\n\t * Restore body scroll\n\t * @memberof ReferencesDrawer\n\t * @instance\n\t */\n\tonHide: function () {\n\t\tutil.getDocument().find( 'body' ).removeClass( 'drawer-enabled' );\n\t},\n\t/**\n\t * Fetch and render nested reference upon click\n\t * @memberof ReferencesDrawer\n\t * @instance\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 * @return {jQuery.Deferred}\n\t */\n\tshowReference: function ( id, page, refNumber ) {\n\t\tvar drawer = this,\n\t\t\tgateway = this.options.gateway;\n\n\t\t// Save the page in case we have to show a nested reference.\n\t\tthis.options.page = page;\n\t\t// If API is being used we want to show the drawer with the spinner while query runs\n\t\tdrawer.show();\n\t\treturn gateway.getReference( id, page ).then( function ( reference ) {\n\t\t\tdrawer.render( {\n\t\t\t\ttitle: refNumber,\n\t\t\t\ttext: reference.text\n\t\t\t} );\n\t\t}, function ( err ) {\n\t\t\tif ( err === ReferencesGateway.ERROR_NOT_EXIST ) {\n\t\t\t\tdrawer.hide();\n\t\t\t} else {\n\t\t\t\tdrawer.render( {\n\t\t\t\t\terror: true,\n\t\t\t\t\ttitle: refNumber,\n\t\t\t\t\ttext: mw.msg( 'mobile-frontend-references-citation-error' )\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\t},\n\t/**\n\t * Fetch and render nested reference upon click\n\t * @memberof ReferencesDrawer\n\t * @instance\n\t * @param {jQuery.Event} ev\n\t * @return {boolean} False to cancel the native event\n\t */\n\tshowNestedReference: function ( ev ) {\n\t\tvar $dest = this.$el.find( ev.target );\n\n\t\tthis.showReference( $dest.attr( 'href' ), this.options.page, $dest.text() );\n\t\t// Don't hide the already shown drawer via propagation\n\t\t// and stop default scroll behaviour.\n\t\treturn false;\n\t}\n} );\n\nmodule.exports = ReferencesDrawer;\n","/**\n * Abstract base class\n * Gateway for retrieving references\n *\n * @class ReferencesGateway\n * @abstract\n *\n * @param {mw.Api} api\n */\nfunction ReferencesGateway( api ) {\n\tthis.api = api;\n}\n\n/**\n * Return the matched reference via API or DOM query\n *\n * @memberof ReferencesGateway\n * @instance\n * @param {string} id CSS selector\n * @param {Page} page to find reference for\n * @return {jQuery.Promise} resolves with an Object representing reference\n *  with a `text` property\n *  The promise should be rejected with ReferenceGateway.ERROR_NOT_EXIST:\n *  if the reference is not found.\n *  If for some reason locating the reference fails return ReferenceGateway.ERROR_OTHER.\n */\nReferencesGateway.prototype.getReference = null;\n\n/**\n * @memberof ReferencesGateway\n * @property ERROR_NOT_EXIST error code to be returned by getReference\n *  when a reference does not exist.\n */\nReferencesGateway.ERROR_NOT_EXIST = 'NOT_EXIST_ERROR';\n/**\n * @memberof ReferencesGateway\n * @property 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 */\nReferencesGateway.ERROR_OTHER = 'OTHER_ERROR';\n\nmodule.exports = ReferencesGateway;\n","var ReferencesGateway = require( './ReferencesGateway' ),\n\tmfExtend = require( './../mfExtend' ),\n\tutil = require( './../util' );\n\n/**\n * Gateway for retrieving references via the content of the Page\n *\n * @class ReferencesHtmlScraperGateway\n * @extends ReferencesGateway\n * @inheritdoc\n */\nfunction ReferencesHtmlScraperGateway() {\n\tReferencesGateway.apply( this, arguments );\n}\n\nmfExtend( ReferencesHtmlScraperGateway, ReferencesGateway, {\n\t/**\n\t * @memberof ReferencesHtmlScraperGateway\n\t * @instance\n\t * @param {string} id of a DOM element in the page with '#' prefix.\n\t *  can be encoded or decoded.\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: function ( id, $container ) {\n\t\tvar $el,\n\t\t\tresult = util.Deferred();\n\n\t\t$el = $container.find( '#' + util.escapeSelector( id.substr( 1 ) ) );\n\t\tif ( $el.length ) {\n\t\t\tresult.resolve( { text: $el.html() } );\n\t\t} else {\n\t\t\tresult.reject( ReferencesGateway.ERROR_NOT_EXIST );\n\t\t}\n\t\treturn result.promise();\n\t},\n\t/**\n\t * @inheritdoc\n\t * @memberof ReferencesHtmlScraperGateway\n\t * @instance\n\t */\n\tgetReference: function ( id, page ) {\n\t\t// If an id is not found it's possible the id passed needs decoding (per T188547).\n\t\treturn this.getReferenceFromContainer( decodeURIComponent( id ), page.$el.find( 'ol.references' ) );\n\t}\n} );\n\nmodule.exports = ReferencesHtmlScraperGateway;\n","var ReferencesHtmlScraperGateway =\n\trequire( './ReferencesHtmlScraperGateway' ),\n\tcache = require( './../cache' ),\n\tReferencesGateway = require( './ReferencesGateway' ),\n\tMemoryCache = cache.MemoryCache,\n\tutil = require( './../util' ),\n\tmfExtend = require( './../mfExtend' ),\n\tNoCache = cache.NoCache,\n\treferencesMobileViewGateway = null;\n\n/**\n * Gateway for retrieving references via the MobileView API\n *\n * By default not cached, if it receives a cache instance then it will be\n * used to store and get references sections.\n *\n * @class ReferencesMobileViewGateway\n * @extends ReferencesHtmlScraperGateway\n * @inheritdoc\n *\n * @param {mw.Api} api class to use for making requests\n * @param {NoCache|MemoryCache} [cache] class to use for caching request\n * results. By default it uses the NoCache implementation, which doesn't\n * cache anything. The singleton instance exposed by this module uses\n * a MemoryCache which caches requests in-memory. Any other Cache class\n * compatible with mobile.startup/cache's interface will actually work.\n */\nfunction ReferencesMobileViewGateway( api, cache ) {\n\tReferencesHtmlScraperGateway.call( this, api );\n\tthis.cache = cache || new NoCache();\n}\n\nmfExtend( ReferencesMobileViewGateway, ReferencesHtmlScraperGateway, {\n\t/**\n\t * Retrieve references list for a given page.\n\t * Also cache the result for a later use.\n\t *\n\t * @memberof ReferencesMobileViewGateway\n\t * @instance\n\t * @param {Page} page\n\t * @return {jQuery.Deferred} promise that resolves with the list of\n\t *  sections on the page\n\t */\n\tgetReferencesLists: function ( page ) {\n\t\tvar self = this,\n\t\t\tresult = util.Deferred(),\n\t\t\tcachedReferencesSections = this.cache.get( page.id );\n\n\t\tif ( cachedReferencesSections ) {\n\t\t\treturn result.resolve( cachedReferencesSections ).promise();\n\t\t}\n\n\t\tthis.api.get( {\n\t\t\taction: 'mobileview',\n\t\t\tpage: page.getTitle(),\n\t\t\tsections: 'references',\n\t\t\tprop: 'text',\n\t\t\trevision: page.getRevisionId()\n\t\t} ).then( function ( data ) {\n\t\t\tvar sections = {};\n\n\t\t\tdata.mobileview.sections.forEach( function ( section ) {\n\t\t\t\tvar $section = util.parseHTML( '<div>' ).html( section.text );\n\n\t\t\t\tsections[ $section.find( '.mw-headline' ).attr( 'id' ) ] = $section.find( '.references' );\n\t\t\t} );\n\n\t\t\tself.cache.set( page.id, sections );\n\t\t\tresult.resolve( sections );\n\t\t}, function () {\n\t\t\tresult.reject( ReferencesGateway.ERROR_OTHER );\n\t\t} );\n\n\t\treturn result.promise();\n\t},\n\t/**\n\t * Retrieve all the references lists for a given page and section ID.\n\t *\n\t * @memberof ReferencesMobileViewGateway\n\t * @instance\n\t * @param {Page} page\n\t * @param {string} headingId\n\t * @return {jQuery.Promise} promise that resolves with the section\n\t *  HTML or `false` if no such section exists\n\t */\n\tgetReferencesList: function ( page, headingId ) {\n\t\treturn this.getReferencesLists( page ).then( function ( data ) {\n\t\t\treturn Object.prototype.hasOwnProperty.call( data, headingId ) ?\n\t\t\t\tdata[ headingId ] : false;\n\t\t} );\n\t},\n\t/**\n\t * @inheritdoc\n\t * @memberof ReferencesMobileViewGateway\n\t * @instance\n\t */\n\tgetReference: function ( id, page ) {\n\t\tvar self = this;\n\n\t\treturn this.getReferencesLists( page ).then( function ( sections ) {\n\t\t\tvar $container = util.parseHTML( '<div>' );\n\n\t\t\tObject.keys( sections ).forEach( function ( sectionId ) {\n\t\t\t\t$container.append( sections[ sectionId ] );\n\t\t\t} );\n\n\t\t\treturn self.getReferenceFromContainer( id, $container );\n\t\t} );\n\t}\n} );\n\n/**\n * Retrieve a singleton instance w/ cache that uses mw.Api\n * @memberof ReferencesMobileViewGateway\n * @return {ReferencesMobileViewGateway}\n */\nReferencesMobileViewGateway.getSingleton = function () {\n\tif ( !referencesMobileViewGateway ) {\n\t\treferencesMobileViewGateway = new ReferencesMobileViewGateway(\n\t\t\tnew mw.Api(),\n\t\t\tnew MemoryCache()\n\t\t);\n\t}\n\treturn referencesMobileViewGateway;\n};\n\nmodule.exports = ReferencesMobileViewGateway;\n","var\n\tloadingOverlay = require( './loadingOverlay' ),\n\tutil = require( './util' );\n\n/**\n * Utility library for looking up details on the current user\n * @class loader\n * @singleton\n */\nmodule.exports = {\n\t// Exported to support testing and stubbing\n\tnewLoadingOverlay: function () {\n\t\treturn loadingOverlay();\n\t},\n\t/**\n\t * Loads a module via ResourceLoader\n\t * and displays a full screen LoadingOverlay during load time.\n\t * @memberof loader\n\t * @instance\n\t * @param {string} name ResourceLoader module name to load asynchronously.\n\t * @param {boolean} delegateHide if true the caller is responsible for hiding\n\t *  the intermediate loader.\n\t * @param {boolean} [showLoadingOverlay] if false a loading overlay will be hidden while\n\t *  loading the module. Defaults to true.\n\t * @return {jQuery.Promise}\n\t */\n\tloadModule: function ( name, delegateHide, showLoadingOverlay ) {\n\t\tvar loadingOverlay = this.newLoadingOverlay();\n\n\t\tshowLoadingOverlay = ( showLoadingOverlay !== undefined ) ? showLoadingOverlay : true;\n\t\tif ( showLoadingOverlay ) {\n\t\t\tloadingOverlay.appendTo( document.body );\n\t\t\tloadingOverlay.show();\n\t\t}\n\n\t\tfunction hideOverlayIfNeeded() {\n\t\t\tif ( !delegateHide && showLoadingOverlay ) {\n\t\t\t\tloadingOverlay.hide();\n\t\t\t}\n\t\t}\n\t\treturn mw.loader.using( name ).then( function () {\n\t\t\thideOverlayIfNeeded();\n\n\t\t\treturn loadingOverlay;\n\t\t}, function () {\n\t\t\thideOverlayIfNeeded();\n\n\t\t\treturn util.Deferred().reject().promise();\n\t\t} );\n\t}\n};\n","/**\n * Coordinates the logging of MobileWebSchema events.\n * Implements schema defined at https://meta.wikimedia.org/wiki/Schema:MobileWebSearch\n *\n * @class\n */\nfunction MobileWebSearchLogger() {\n\tthis.userSessionToken = null;\n\tthis.searchSessionToken = null;\n}\n\nMobileWebSearchLogger.prototype = {\n\t/**\n\t * Sets the internal state required to deal with logging user session\n\t * data.\n\t * @memberof MobileWebSearchLogger\n\t * @instance\n\t * @private\n\t */\n\t_newUserSession: function () {\n\t\tthis.userSessionToken = mw.user.generateRandomSessionId();\n\t},\n\n\t/**\n\t * Sets the internal state required to deal with logging search session\n\t * data.\n\t * @memberof MobileWebSearchLogger\n\t * @instance\n\t * @private\n\t */\n\t_newSearchSession: function () {\n\t\tthis.searchSessionToken = mw.user.generateRandomSessionId();\n\t\tthis.searchSessionCreatedAt = new Date().getTime();\n\t},\n\n\t/**\n\t * Handles the 'search-show' event.\n\t * @memberof MobileWebSearchLogger\n\t * @instance\n\t */\n\tonSearchShow: function () {\n\t\tthis._newUserSession();\n\t},\n\n\t/**\n\t * Handles the 'search-start' event.\n\t * @memberof MobileWebSearchLogger\n\t * @instance\n\t */\n\tonSearchStart: function () {\n\t\tthis._newSearchSession();\n\t\tmw.track( 'mf.schemaMobileWebSearch', {\n\t\t\taction: 'session-start',\n\t\t\tuserSessionToken: this.userSessionToken,\n\t\t\tsearchSessionToken: this.searchSessionToken,\n\t\t\ttimeOffsetSinceStart: 0\n\t\t} );\n\t},\n\n\t/**\n\t * Handles the 'search-results' event.\n\t * @memberof MobileWebSearchLogger\n\t * @instance\n\t * @param {Object} event with property {Object[]} event.results\n\t */\n\tonSearchResults: function ( event ) {\n\t\tvar timeOffsetSinceStart =\n\t\t\tnew Date().getTime() - this.searchSessionCreatedAt;\n\n\t\tmw.track( 'mf.schemaMobileWebSearch', {\n\t\t\taction: 'impression-results',\n\t\t\tresultSetType: 'prefix',\n\t\t\tnumberOfResults: event.results.length,\n\t\t\tuserSessionToken: this.userSessionToken,\n\t\t\tsearchSessionToken: this.searchSessionToken,\n\t\t\t// FIXME: Unless I'm mistaken, the timeToDisplayResults\n\t\t\t// property isn't necessary.\n\t\t\ttimeToDisplayResults: timeOffsetSinceStart,\n\t\t\ttimeOffsetSinceStart: timeOffsetSinceStart\n\t\t} );\n\t},\n\n\t/**\n\t * Handles the 'search-result-click' event.\n\t * @memberof MobileWebSearchLogger\n\t * @instance\n\t * @param {Object} event with property {number} event.index\n\t *  The zero-based index of the result in the set of results.\n\t */\n\tonSearchResultClick: function ( event ) {\n\t\tvar timeOffsetSinceStart =\n\t\t\tnew Date().getTime() - this.searchSessionCreatedAt;\n\n\t\tmw.track( 'mf.schemaMobileWebSearch', {\n\t\t\taction: 'click-result',\n\t\t\t// NOTE: clickIndex is 1-based.\n\t\t\tclickIndex: event.resultIndex + 1,\n\t\t\tuserSessionToken: this.userSessionToken,\n\t\t\tsearchSessionToken: this.searchSessionToken,\n\t\t\ttimeOffsetSinceStart: timeOffsetSinceStart\n\t\t} );\n\t}\n};\n\n/**\n * Convenience function that wires up an instance of the\n * MobileWebSearchLogger class to the search-* events emitted by the\n * search overlay.\n * @memberof MobileWebSearchLogger\n * @param {SearchOverlay} searchOverlay\n */\nMobileWebSearchLogger.register = function ( searchOverlay ) {\n\tvar logger = new MobileWebSearchLogger();\n\n\tsearchOverlay.on( 'search-show', logger.onSearchShow.bind( logger ) );\n\tsearchOverlay.on( 'search-start', logger.onSearchStart.bind( logger ) );\n\tsearchOverlay.on( 'search-results', logger.onSearchResults.bind( logger ) );\n\tsearchOverlay.on( 'search-result-click', logger.onSearchResultClick.bind( logger ) );\n};\n\nmodule.exports = MobileWebSearchLogger;\n","var\n\tPage = require( '../Page' ),\n\tutil = require( '../util' ),\n\textendSearchParams = require( '../extendSearchParams' );\n\n/**\n * @class SearchGateway\n * @uses mw.Api\n * @param {mw.Api} api\n */\nfunction SearchGateway( api ) {\n\tthis.api = api;\n\tthis.searchCache = {};\n\tthis.generator = mw.config.get( 'wgMFSearchGenerator' );\n}\n\nSearchGateway.prototype = {\n\t/**\n\t * The namespace to search in.\n\t * @memberof SearchGateway\n\t * @instance\n\t * @type {number}\n\t */\n\tsearchNamespace: 0,\n\n\t/**\n\t * Get the data used to do the search query api call.\n\t * @memberof SearchGateway\n\t * @instance\n\t * @param {string} query to search for\n\t * @return {Object}\n\t */\n\tgetApiData: function ( query ) {\n\t\tvar 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 * @memberof SearchGateway\n\t * @instance\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: function ( 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 * @memberof SearchGateway\n\t * @instance\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: function ( label, term ) {\n\t\tlabel = util.parseHTML( '<span>' ).text( label ).html();\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 * @memberof SearchGateway\n\t * @instance\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: function ( query, pageInfo ) {\n\t\tvar page = Page.newFromJSON( 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 * @memberof SearchGateway\n\t * @instance\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: function ( query, data ) {\n\t\tvar self = this,\n\t\t\tresults = [];\n\n\t\tif ( data.query ) {\n\n\t\t\tresults = data.query.pages || {};\n\t\t\tresults = Object.keys( results ).map( function ( id ) {\n\t\t\t\treturn self._getPage( query, results[ id ] );\n\t\t\t} );\n\t\t\t// sort in order of index\n\t\t\tresults.sort( function ( a, b ) {\n\t\t\t\treturn a.index < b.index ? -1 : 1;\n\t\t\t} );\n\t\t}\n\n\t\treturn results;\n\t},\n\n\t/**\n\t * Perform a search for the given query.\n\t * @memberof SearchGateway\n\t * @instance\n\t * @param {string} query to search for\n\t * @return {jQuery.Deferred}\n\t */\n\tsearch: function ( query ) {\n\t\tvar xhr, request,\n\t\t\tself = this;\n\n\t\tif ( !this.isCached( query ) ) {\n\t\t\txhr = this.api.get( this.getApiData( query ) );\n\t\t\trequest = xhr\n\t\t\t\t.then( function ( data ) {\n\t\t\t\t\t// resolve the Deferred object\n\t\t\t\t\treturn {\n\t\t\t\t\t\tquery: query,\n\t\t\t\t\t\tresults: self._processData( query, data )\n\t\t\t\t\t};\n\t\t\t\t}, function () {\n\t\t\t\t\t// reset cached result, it maybe contains no value\n\t\t\t\t\tself.searchCache[query] = undefined;\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: function () { xhr.abort(); }\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 * @memberof SearchGateway\n\t * @instance\n\t * @param {string} query\n\t * @return {boolean}\n\t */\n\tisCached: function ( query ) {\n\t\treturn Boolean( this.searchCache[ query ] );\n\t}\n};\n\nmodule.exports = SearchGateway;\n","var m = require( '../moduleLoaderSingleton' ),\n\tpromisedView = require( '../promisedView' ),\n\tAnchor = require( '../Anchor' ),\n\tutil = require( '../util' ),\n\tOverlay = require( '../Overlay' );\n\n/**\n * Produce an overlay for talk page\n * @param {string} title of the page to get talk topics for\n * @param {PageGateway} gateway for interacting with API.\n * @return {Overlay}\n */\nfunction talkOverlay( title, gateway ) {\n\tvar user = mw.user;\n\n\treturn Overlay.make(\n\t\t{\n\t\t\theading: '<strong>' + mw.msg( 'mobile-frontend-talk-overlay-header' ) + '</strong>',\n\t\t\theaderButtons: [ user.isAnon() ? {} : {\n\t\t\t\thref: '#/talk/new',\n\t\t\t\tclassName: 'continue',\n\t\t\t\tmsg: mw.msg( 'mobile-frontend-talk-add-overlay-submit' )\n\t\t\t} ],\n\t\t\tfooterAnchor: new Anchor( {\n\t\t\t\tprogressive: true,\n\t\t\t\thref: mw.util.getUrl( title ),\n\t\t\t\tadditionalClassNames: 'footer-link talk-fullpage',\n\t\t\t\tlabel: mw.msg( 'mobile-frontend-talk-fullpage' )\n\t\t\t} ).options,\n\t\t\tclassName: 'talk-overlay overlay'\n\t\t},\n\t\tpromisedView(\n\t\t\tutil.Promise.all( [\n\t\t\t\tgateway.getSections( title ),\n\t\t\t\tmw.loader.using( 'mobile.talk.overlays' )\n\t\t\t] ).then( function ( sections ) {\n\t\t\t\tvar talkBoard = m.require( 'mobile.talk.overlays/talkBoard' );\n\t\t\t\treturn talkBoard( sections );\n\t\t\t} )\n\t\t)\n\t);\n}\n\nmodule.exports = talkOverlay;\n","var units = [ 'seconds', 'minutes', 'hours', 'days', 'months', 'years' ],\n\tutil = require( './util' ),\n\tlimits = [ 1, 60, 3600, 86400, 2592000, 31536000 ];\n\n/** @class time */\n\n/**\n * Calculate the correct unit of timestamp\n * @memberof time\n * @instance\n * @param {number} timestampDelta\n * @return {{value: number, unit: string}}\n */\nfunction timeAgo( timestampDelta ) {\n\tvar 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 * @memberof time\n * @instance\n * @param {number} timestamp\n * @return {{value: number, unit: string}}\n */\nfunction getTimeAgoDelta( timestamp ) {\n\tvar currentTimestamp = Math.round( new Date().getTime() / 1000 );\n\n\treturn timeAgo( currentTimestamp - timestamp );\n}\n\n/**\n * Whether timestamp delta is less than a day old\n * @memberof time\n * @instance\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 * @memberof time\n * @instance\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 * @memberof time\n * @instance\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, if omitted\n *  returns plain text string rather than html\n * @return {string}\n */\nfunction getLastModifiedMessage( ts, username, gender, historyUrl ) {\n\tvar delta, html,\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\tdelta = 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\targs.push(\n\t\thistoryUrl || '#',\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 ? mw.util.getUrl( 'User:' + username ) : ''\n\t);\n\thtml = mw.message.apply( this, args ).parse();\n\tif ( historyUrl ) {\n\t\treturn html;\n\t} else {\n\t\treturn util.parseHTML( '<div>' ).html( html ).text();\n\t}\n}\n\n/**\n * Return a message relating to the registration date of the user\n * @memberof time\n * @instance\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\tvar delta, html,\n\t\tkeys = {\n\t\t\tseconds: 'mobile-frontend-joined-seconds',\n\t\t\tminutes: 'mobile-frontend-joined-minutes',\n\t\t\thours: 'mobile-frontend-joined-hours',\n\t\t\tdays: 'mobile-frontend-joined-days',\n\t\t\tmonths: 'mobile-frontend-joined-months',\n\t\t\tyears: 'mobile-frontend-joined-years'\n\t\t},\n\t\targs = [];\n\n\tgender = gender || 'unknown';\n\n\tdelta = 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\thtml = mw.message.apply( this, args ).parse();\n\treturn html;\n}\n\nmodule.exports = {\n\tgetLastModifiedMessage: getLastModifiedMessage,\n\tgetRegistrationMessage: getRegistrationMessage,\n\ttimeAgo: timeAgo,\n\tgetTimeAgoDelta: getTimeAgoDelta,\n\tisNow: isNow,\n\tisRecent: isRecent\n};\n","var\n\tutil = require( './util' ),\n\tstorageKey = 'mobileFrontend/toast';\n\n/**\n * Wrapper for one global Toast\n * @class Toast\n */\nfunction Toast() {\n\tmw.requestIdleCallback( this._showPending.bind( this ) );\n}\n\n/**\n * Show a message with the given class in a toast.\n * @memberof Toast\n * @instance\n * @param {string} msg Message to show in the toast\n * @param {Object|string} [options]\n *  If a string (deprecated) CSS class to add to the element\n *  If an object, more options for the notification see mw.notification.show.\n *  For backwards compatibility reasons if a string is given it will be\n *  treated as options.type\n */\nToast.prototype.show = function ( msg, options ) {\n\tif ( typeof options === 'string' ) {\n\t\tmw.log.warn( 'The use of the cssClass parameter of Toast.show is deprecated, please convert it to an ' +\n\t\t\t\t'options object.' );\n\t\toptions = {\n\t\t\ttype: options\n\t\t};\n\t}\n\n\toptions = util.extend( {\n\t\ttag: 'toast'\n\t}, options );\n\n\tthis.notification = mw.notify( msg, options );\n};\n\n/**\n * Hide the Toast if it's visible.\n * @memberof Toast\n * @instance\n */\nToast.prototype.hide = function () {\n\tif ( this.notification !== undefined ) {\n\t\tthis.notification.then( function ( notif ) {\n\t\t\tnotif.close();\n\t\t} );\n\t}\n};\n\n/**\n * Save the toast data in storage so that we can show it on page reload.\n * Also check whether there is a pending message that's not shown yet.\n * If yes, output a warning message and discard this message.\n * This is to ensure that the page needs to be reloaded before adding\n * a new message for showing later.\n * @memberof Toast\n * @instance\n * @param {string} content Content to be placed in element\n * @param {Object|string} [options]\n *  If a string (deprecated) CSS class to add to the element\n *  If an object, more options for the notification see mw.notification.show.\n *  For backwards compatibility reasons if a string is given it will be\n *  treated as options.type\n */\nToast.prototype.showOnPageReload = function ( content, options ) {\n\tif ( mw.storage.get( storageKey ) ) {\n\t\tmw.log.warn(\n\t\t\t'A pending toast message already exits. ' +\n\t\t\t\t'The page should have been reloaded by now.'\n\t\t);\n\t\treturn;\n\t}\n\tmw.storage.set( storageKey, JSON.stringify( {\n\t\tcontent: content,\n\t\toptions: options\n\t} ) );\n};\n\n/**\n * Show the previously saved toast data and delete it from storage\n * @memberof Toast\n * @instance\n * @private\n */\nToast.prototype._showPending = function () {\n\tvar data = mw.storage.get( storageKey );\n\tif ( data ) {\n\t\tdata = JSON.parse( data );\n\t\tthis.show( data.content, data.options );\n\t\tmw.storage.remove( storageKey );\n\t}\n};\n\nmodule.exports = new Toast();\n","/* global $ */\n\n/**\n * Utility library\n * @class util\n * @singleton\n */\nmodule.exports = {\n\t/**\n\t * Wrapper class for Promises\n\t * @memberof util\n\t * @instance\n\t */\n\tPromise: {\n\t\t/**\n\t\t * Wrapper class for the $.when that is compatible with Promise.all\n\t\t * @memberof util\n\t\t * @param {jQuery.Promise[]} promises\n\t\t * @instance\n\t\t * @return {jQuery.Promise}\n\t\t */\n\t\tall: function ( promises ) {\n\t\t\treturn $.when.apply( $, promises );\n\t\t}\n\t},\n\t/**\n\t * Escape a string for use as a css selector\n\t * @memberof util\n\t * @instance\n\t * @param {string} selector\n\t * @return {string}\n\t */\n\tescapeSelector: function ( selector ) {\n\t\treturn $.escapeSelector( selector );\n\t},\n\t/**\n\t * Wrapper class for the $.grep\n\t * @memberof util\n\t * @instance\n\t * @return {jQuery.Deferred}\n\t */\n\tgrep: function () {\n\t\treturn $.grep.apply( $, arguments );\n\t},\n\t/**\n\t * Run method when document is ready.\n\t * @memberof util\n\t * @instance\n\t * @param {Function} fn\n\t * @return {jQuery.Object}\n\t */\n\tdocReady: function ( fn ) {\n\t\treturn $( fn );\n\t},\n\t/**\n\t * Wrapper class for the Deferred method\n\t * @memberof util\n\t * @instance\n\t * @return {jQuery.Deferred}\n\t */\n\tDeferred: function () {\n\t\treturn $.Deferred();\n\t},\n\t/**\n\t * Adds a class to the document\n\t * @memberof util\n\t * @instance\n\t * @return {jQuery.Object} element representing the documentElement\n\t */\n\tgetDocument: function () {\n\t\treturn $( document.documentElement );\n\t},\n\t/**\n\t * Get the window object\n\t * @memberof util\n\t * @instance\n\t * @return {jQuery.Object}\n\t */\n\tgetWindow: function () {\n\t\treturn $( window );\n\t},\n\t/**\n\t * Given some html, create new element(s).\n\t * Unlike jQuery.parseHTML this will return a jQuery object\n\t * not an array.\n\t * @memberof util\n\t * @instance\n\t * @param {string} html\n\t * @param {Element} [ctx] Document element to serve as the context\n\t *  in which the HTML fragment will be created\n\t * @return {jQuery.Object}\n\t */\n\tparseHTML: function ( html, ctx ) {\n\t\tctx = ctx || document;\n\t\treturn $( $.parseHTML( html, ctx ) );\n\t},\n\t/**\n\t * wrapper for jQuery util function to check if something is numeric\n\t * @memberof util\n\t * @instance\n\t * @return {boolean}\n\t */\n\tisNumeric: function () {\n\t\treturn $.isNumeric.apply( $, arguments );\n\t},\n\t/**\n\t * Wrapper for jQuery.extend method. In future this can be bound to Object.assign\n\t * when support allows.\n\t *\n\t * Warning: if only one argument is supplied to util.extend(), this means the target argument\n\t * was omitted. In this case, the jQuery object itself is assumed to be the target.\n\t *\n\t * @memberof util\n\t * @instance\n\t * @return {Object}\n\t */\n\textend: function () {\n\t\treturn $.extend.apply( $, arguments );\n\t},\n\t/**\n\t * Escape dots and colons in a hash, jQuery doesn't like them because they\n\t * look like CSS classes and pseudoclasses. See\n\t * http://bugs.jquery.com/ticket/5241\n\t * http://stackoverflow.com/questions/350292/how-do-i-get-jquery-to-select-elements-with-a-period-in-their-id\n\t * @memberof util\n\t * @instance\n\t * @param {string} hash A hash to escape\n\t * @return {string}\n\t */\n\tescapeHash: function ( hash ) {\n\t\treturn hash.replace( /(:|\\.)/g, '\\\\$1' );\n\t},\n\n\t/**\n\t * Heuristic for determining whether an Event should be handled by\n\t * MobileFrontend or allowed to bubble to the browser.\n\t * @memberof util\n\t * @instance\n\t * @param {Event} ev\n\t * @return {boolean} True if event is modified with control, alt, meta, or\n\t *                   shift keys and should probably be handled by the\n\t *                   browser.\n\t *\n\t * todo: move this function to a ClickUtil file once bundling and code\n\t * splitting is supported.\n\t */\n\tisModifiedEvent: function ( ev ) {\n\t\treturn ev.altKey || ev.ctrlKey || ev.metaKey || ev.shiftKey;\n\t},\n\n\t/**\n\t * Pipe event emitted by source through proxy. Subscribers to proxy will receive the event as\n\t * though proxy was the originator.\n\t *\n\t * @param {OO.EventEmitter} src\n\t * @param {OO.EventEmitter} proxy\n\t * @param {string} event Event type to listen for.\n\t * @param {any[]} [args] Arguments to pass to\n\t *  subscribers, will be prepended to emitted arguments.\n\t * @return {OO.EventEmitter} The source.\n\t */\n\trepeatEvent: function ( src, proxy, event, args ) {\n\t\treturn src.on( event, function ( args ) {\n\t\t\treturn proxy.emit( event, args );\n\t\t}, args );\n\t}\n};\n","var View = require( '../View' ),\n\tWatchstarGateway = require( './WatchstarGateway' ),\n\ticons = require( '../icons' ),\n\tutil = require( '../util' ),\n\tmfExtend = require( '../mfExtend' ),\n\ttoast = require( '../toast' ),\n\tCtaDrawer = require( '../CtaDrawer' );\n\n/**\n * A clickable watchstar\n * @class Watchstar\n * @extends View\n * @uses CtaDrawer\n * @uses Icon\n * @uses WatchstarGateway\n * @uses Toast\n * @fires Watchstar#unwatch\n * @fires Watchstar#watch\n *\n * @param {Object} options Configuration options\n */\nfunction Watchstar( options ) {\n\tView.call(\n\t\tthis,\n\t\tutil.extend(\n\t\t\ttrue,\n\t\t\t{\n\t\t\t\tclassName: icons.watchIcon().getClassName(),\n\t\t\t\tevents: {\n\t\t\t\t\tclick: 'onStatusToggle'\n\t\t\t\t}\n\t\t\t},\n\t\t\toptions\n\t\t)\n\t);\n}\n\nmfExtend( Watchstar, View, {\n\t/**\n\t * @memberof Watchstar\n\t * @instance\n\t * @mixes View#defaults\n\t * @property {Object} defaults Default options hash.\n\t * @property {mw.Api} defaults.api\n\t * @property {Page} defaults.page Current page.\n\t * @property {string} defaults.funnel to log events with\n\t */\n\tdefaults: {\n\t\tpage: undefined,\n\t\tfunnel: 'unknown'\n\t},\n\t/**\n\t * @memberof Watchstar\n\t * @instance\n\t * @property {Object} ctaDrawerOptions Default options hash for the anonymous CtaDrawer.\n\t */\n\tctaDrawerOptions: {\n\t\tcontent: mw.msg( 'mobile-frontend-watchlist-cta' ),\n\t\tqueryParams: {\n\t\t\twarning: 'mobile-frontend-watchlist-purpose',\n\t\t\tcampaign: 'mobile_watchPageActionCta',\n\t\t\treturntoquery: 'article_action=watch'\n\t\t},\n\t\tsignupQueryParams: {\n\t\t\twarning: 'mobile-frontend-watchlist-signup-action'\n\t\t}\n\t},\n\t/**\n\t * @inheritdoc\n\t * @memberof Watchstar\n\t * @instance\n\t */\n\tinitialize: function ( options ) {\n\t\tvar self = this,\n\t\t\t_super = View.prototype.initialize;\n\n\t\tthis._watched = options.isWatched;\n\t\tthis.gateway = new WatchstarGateway( options.api );\n\n\t\t_super.call( self, options );\n\t},\n\t/**\n\t * @inheritdoc\n\t * @memberof Watchstar\n\t * @instance\n\t */\n\tpreRender: function () {\n\t\tthis.options.tooltip = this._watched ? mw.msg( 'unwatchthispage' ) : mw.msg( 'watchthispage' );\n\t},\n\t/**\n\t * @inheritdoc\n\t * @memberof Watchstar\n\t * @instance\n\t */\n\tpostRender: function () {\n\t\tvar unwatchedClass = icons.watchIcon().getGlyphClassName(),\n\t\t\twatchedClass = icons.watchedIcon().getGlyphClassName() + ' watched';\n\n\t\tthis.$el.text( this.options.tooltip );\n\n\t\t// Add watched class if necessary\n\t\tif ( !mw.user.isAnon() && this._watched ) {\n\t\t\tthis.$el.addClass( watchedClass ).removeClass( unwatchedClass );\n\t\t} else {\n\t\t\tthis.$el.addClass( unwatchedClass ).removeClass( watchedClass );\n\t\t}\n\t\tthis.$el.removeClass( 'hidden' );\n\t},\n\t/**\n\t * Triggered when a user anonymously clicks on the watchstar.\n\t * @memberof Watchstar\n\t * @instance\n\t */\n\tonStatusToggleAnon: function () {\n\t\tif ( !this.drawer ) {\n\t\t\tthis.drawer = new CtaDrawer( this.ctaDrawerOptions );\n\n\t\t}\n\t\tthis.drawer.show();\n\t},\n\n\t/**\n\t * Triggered when a logged in user clicks on the watchstar.\n\t * @memberof Watchstar\n\t * @instance\n\t */\n\tonStatusToggleUser: function () {\n\t\tvar\n\t\t\tself = this,\n\t\t\tgateway = this.gateway,\n\t\t\tpage = this.options.page,\n\t\t\tchecker,\n\t\t\tpostWatched = !this._watched;\n\n\t\tchecker = setInterval( function () {\n\t\t\ttoast.show( mw.msg( 'mobile-frontend-watchlist-please-wait' ) );\n\t\t}, 1000 );\n\t\tfunction stopInterval() {\n\t\t\tclearInterval( checker );\n\t\t}\n\t\tgateway.postStatusesByTitle( [ page.getTitle() ], postWatched ).then( function () {\n\t\t\tstopInterval();\n\n\t\t\tself._watched = postWatched;\n\t\t\tif ( postWatched ) {\n\t\t\t\tself.render();\n\t\t\t\t/**\n\t\t\t\t * Fired when the watch star is changed to watched status\n\t\t\t\t * @event Watchstar#watch\n\t\t\t\t */\n\t\t\t\tself.emit( 'watch' );\n\t\t\t\ttoast.show( mw.msg( 'mobile-frontend-watchlist-add', page.title ) );\n\t\t\t} else {\n\t\t\t\t/**\n\t\t\t\t * Fired when the watch star is changed to unwatched status\n\t\t\t\t * @event Watchstar#unwatch\n\t\t\t\t */\n\t\t\t\tself.emit( 'unwatch' );\n\t\t\t\tself.render();\n\t\t\t\ttoast.show( mw.msg( 'mobile-frontend-watchlist-removed', page.title ) );\n\t\t\t}\n\t\t}, function () {\n\t\t\tstopInterval();\n\n\t\t\ttoast.show( mw.msg( 'mobile-frontend-watchlist-error' ), { type: 'error' } );\n\t\t} );\n\t},\n\n\t/**\n\t * Event handler for clicking on watch star.\n\t * Make an API request if user is not anonymous.\n\t * @memberof Watchstar\n\t * @instance\n\t * @param {jQuery.Event} ev jQuery event object\n\t */\n\tonStatusToggle: function ( ev ) {\n\t\tev.preventDefault();\n\t\tif ( mw.user.isAnon() ) {\n\t\t\tthis.onStatusToggleAnon.apply( this, arguments );\n\t\t} else {\n\t\t\tthis.onStatusToggleUser.apply( this, arguments );\n\t\t}\n\t}\n\n} );\n\nmodule.exports = Watchstar;\n","var util = require( '../util' ),\n\tactionParams = require( '../actionParams' );\n\n/**\n * @typedef {string|number} PageID Page ID. 0 / \"0\" is a special no-ID value.\n * {@link https://www.mediawiki.org/wiki/Manual:Page_table#page_id Page ID}\n *\n * @typedef {string} PageTitle Canonical page title.\n * {@link https://www.mediawiki.org/wiki/Manual:Title.php#Canonical_forms Canonical forms}\n *\n * @typedef {boolean} WatchStatus Page watch status; true if watched, false if\n *                                unwatched.\n * {@link https://www.mediawiki.org/wiki/API:Info API:Info} (see inprop.watched)\n * {@link https://www.mediawiki.org/wiki/API:Watch API:Watch} (see unwatch)\n *\n * @typedef {Object.<PageTitle, WatchStatus>} WatchStatusMap\n */\n\n/**\n * API for retrieving and modifying page watch statuses. This module interacts\n * with two endpoints, API:Info for GETs and API:Watch and for POSTs.\n *\n * @class WatchstarGateway\n * @param {mw.Api} api\n */\nfunction WatchstarGateway( api ) {\n\tthis.api = api;\n}\n\nWatchstarGateway.prototype = {\n\t/**\n\t * Issues zero to two asynchronous HTTP requests for the watch status of\n\t * each page ID and title passed.\n\t *\n\t * Every watch entry has a title but not necessarily a page ID. Entries\n\t * without IDs are missing pages, i.e., pages that do not exist. These\n\t * entries are used to observe when a page with a given title is created.\n\t * Although it is convenient to use titles because they're always present,\n\t * IDs are preferred since they're far less likely to exceed the URL length\n\t * limit.\n\t *\n\t * No request is issued when no IDs and no titles are passed. Given that the\n\t * server state does not change between the two requests, overlapping title\n\t * and ID members will behave as expected but there is no reason to issue\n\t * such a request.\n\t *\n\t * @memberof WatchstarGateway\n\t * @instance\n\t * @param {PageID[]} ids\n\t * @param {PageTitle[]} titles\n\t * @return {JQuery.Deferred<WatchStatusMap>}\n\t */\n\tgetStatuses: function ( ids, titles ) {\n\t\t// Issue two requests and coalesce the results.\n\t\treturn util.Promise.all( [\n\t\t\tthis.getStatusesByID( ids ),\n\t\t\tthis.getStatusesByTitle( titles )\n\t\t] ).then( function () { return util.extend.apply( util, arguments ); } );\n\t},\n\n\t/**\n\t * @memberof WatchstarGateway\n\t * @instance\n\t * @param {PageID[]} ids\n\t * @return {JQuery.Deferred<WatchStatusMap>}\n\t */\n\tgetStatusesByID: function ( ids ) {\n\t\tvar self = this;\n\t\tif ( !ids.length ) {\n\t\t\treturn util.Deferred().resolve( {} );\n\t\t}\n\n\t\treturn this.api.get( {\n\t\t\tformatversion: 2,\n\t\t\taction: 'query',\n\t\t\tprop: 'info',\n\t\t\tinprop: 'watched',\n\t\t\tpageids: ids\n\t\t} ).then( function ( rsp ) {\n\t\t\treturn self._unmarshalGetResponse( rsp );\n\t\t} );\n\t},\n\n\t/**\n\t * @memberof WatchstarGateway\n\t * @instance\n\t * @param {PageTitle[]} titles\n\t * @return {JQuery.Deferred<WatchStatusMap>}\n\t */\n\tgetStatusesByTitle: function ( titles ) {\n\t\tvar self = this;\n\t\tif ( !titles.length ) {\n\t\t\treturn util.Deferred().resolve( {} );\n\t\t}\n\n\t\treturn this.api.get( actionParams( {\n\t\t\tprop: 'info',\n\t\t\tinprop: 'watched',\n\t\t\ttitles: titles\n\t\t} ) ).then( function ( rsp ) {\n\t\t\treturn self._unmarshalGetResponse( rsp );\n\t\t} );\n\t},\n\n\t/**\n\t * @memberof WatchstarGateway\n\t * @instance\n\t * @param {PageTitle[]} titles\n\t * @param {WatchStatus} watched\n\t * @return {JQuery.Deferred}\n\t */\n\tpostStatusesByTitle: function ( titles, watched ) {\n\t\tvar params = {\n\t\t\taction: 'watch',\n\t\t\ttitles: titles\n\t\t};\n\t\tif ( !watched ) {\n\t\t\tparams.unwatch = !watched;\n\t\t}\n\t\treturn this.api.postWithToken( 'watch', params );\n\t},\n\n\t/**\n\t * @memberof WatchstarGateway\n\t * @instance\n\t * @param {Object} rsp The API:Info response.\n\t * @return {JQuery.Deferred<WatchStatusMap>}\n\t * @see getStatusesByID\n\t * @see getStatusesByTitle\n\t */\n\t_unmarshalGetResponse: function ( rsp ) {\n\t\tvar pages = rsp && rsp.query && rsp.query.pages || [];\n\t\treturn pages.reduce( function ( statuses, page ) {\n\t\t\tstatuses[page.title] = page.watched;\n\t\t\treturn statuses;\n\t\t}, {} );\n\t}\n};\n\nmodule.exports = WatchstarGateway;\n","var PageList = require( '../PageList' ),\n\tWatchstar = require( './Watchstar' ),\n\tuser = mw.user,\n\tutil = require( '../util' ),\n\tPage = require( '../Page' ),\n\tmfExtend = require( '../mfExtend' ),\n\tWatchstarGateway = require( './WatchstarGateway' );\n\n/**\n * @typedef {Object.<PageTitle, PageID>} PageTitleToPageIDMap\n */\n\n/**\n * List of items page view\n * @class WatchstarPageList\n * @uses Page\n * @uses WatchstarGateway\n * @uses Watchstar\n * @extends PageList\n *\n * @fires WatchstarPageList#unwatch\n * @fires WatchstarPageList#watch\n * @param {Object} options Configuration options\n */\nfunction WatchstarPageList( options ) {\n\tthis.wsGateway = new WatchstarGateway( options.api );\n\tPageList.apply( this, arguments );\n}\n\nmfExtend( WatchstarPageList, PageList, {\n\t/**\n\t * @memberof WatchstarPageList\n\t * @instance\n\t * @mixes PageList#defaults\n\t * @property {Object} defaults Default options hash.\n\t * @property {mw.Api} defaults.api\n\t */\n\n\tpostRender: function () {\n\t\tvar\n\t\t\tself = this,\n\t\t\t$items,\n\t\t\tpages,\n\t\t\tids = [],\n\t\t\ttitles = [];\n\n\t\tPageList.prototype.postRender.apply( this );\n\n\t\t$items = this.queryUnitializedItems();\n\t\tpages = this.parsePagesFromItems( $items );\n\n\t\tObject.keys( pages ).forEach( function ( title ) {\n\t\t\tvar id = pages[title];\n\t\t\t// Favor IDs since they're short and unlikely to exceed URL length\n\t\t\t// limits when batched.\n\t\t\tif ( id && id !== '0' ) {\n\t\t\t\t// ID is present and valid.\n\t\t\t\tids.push( id );\n\t\t\t} else {\n\t\t\t\t// Only titles are available for missing pages.\n\t\t\t\ttitles.push( title );\n\t\t\t}\n\t\t} );\n\n\t\treturn this.getPages( ids, titles ).then( function ( statuses ) {\n\t\t\tself.renderItems( $items, statuses );\n\t\t} );\n\t},\n\n\t/**\n\t * @param {JQuery.Element} $items\n\t * @param {WatchStatusMap} statuses\n\t * @return {void}\n\t */\n\tqueryUnitializedItems: function () {\n\t\treturn this.$el.find( 'li:not(.with-watchstar)' );\n\t},\n\n\t/**\n\t * Retrieve pages\n\t *\n\t * @memberof WatchstarPageList\n\t * @instance\n\t * @param {PageID[]} ids\n\t * @param {PageTitle[]} titles\n\t * @return {JQuery.Deferred<WatchStatusMap>}\n\t */\n\tgetPages: function ( ids, titles ) {\n\t\t// Rendering Watchstars for anonymous users is not useful. Short-circuit\n\t\t// the request.\n\t\tif ( user.isAnon() ) {\n\t\t\treturn util.Deferred().resolve( {} );\n\t\t}\n\n\t\treturn this.wsGateway.getStatuses( ids, titles );\n\t},\n\n\t/**\n\t * @param {JQuery.Element} $items\n\t * @return {PageTitleToPageIDMap}\n\t * @memberof WatchstarPageList\n\t * @instance\n\t */\n\tparsePagesFromItems: function ( $items ) {\n\t\tvar\n\t\t\tself = this,\n\t\t\tpages = {};\n\t\t$items.each( function ( _, item ) {\n\t\t\tvar $item = self.$el.find( item );\n\t\t\tpages[ $item.attr( 'title' ) ] = $item.data( 'id' );\n\t\t} );\n\t\treturn pages;\n\t},\n\n\t/**\n\t * @param {JQuery.Element} $items\n\t * @param {WatchStatusMap} statuses\n\t * @return {void}\n\t */\n\trenderItems: function ( $items, statuses ) {\n\t\tvar self = this;\n\n\t\t// Rendering Watchstars for anonymous users is not useful. Nothing to do.\n\t\tif ( user.isAnon() ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Create watch stars for each entry in list\n\t\t$items.each( function ( _, item ) {\n\t\t\tvar\n\t\t\t\t$item = self.$el.find( item ),\n\t\t\t\tpage = new Page( {\n\t\t\t\t\t// FIXME: Set sections so we don't hit the api (hacky)\n\t\t\t\t\tsections: [],\n\t\t\t\t\ttitle: $item.attr( 'title' ),\n\t\t\t\t\tid: $item.data( 'id' )\n\t\t\t\t} ),\n\t\t\t\tel = self.parseHTML( '<div>' ).appendTo( $item ),\n\t\t\t\twatched = statuses[ page.getTitle() ];\n\n\t\t\tself._appendWatchstar( el, page, watched );\n\t\t\t$item.addClass( 'with-watchstar' );\n\t\t} );\n\t},\n\n\t/**\n\t * @param {HTMLElement} el\n\t * @param {Page} page\n\t * @param {WatchStatus} watched\n\t * @return {Watchstar}\n\t */\n\t_appendWatchstar: function ( el, page, watched ) {\n\t\tvar watchstar = new Watchstar( {\n\t\t\tapi: this.options.api,\n\t\t\tfunnel: this.options.funnel,\n\t\t\tisAnon: user.isAnon(),\n\t\t\t// WatchstarPageList.getPages() already retrieved the status of\n\t\t\t// each page. Explicitly set the watch state so another request\n\t\t\t// will not be issued by the Watchstar.\n\t\t\tisWatched: watched,\n\t\t\tpage: page,\n\t\t\tel: el\n\t\t} );\n\n\t\t/**\n\t\t * @event watch\n\t\t * Fired when an article in the PageList is watched.\n\t\t */\n\t\tutil.repeatEvent( watchstar, this, 'watch' );\n\n\t\t/**\n\t\t * @event unwatch\n\t\t * Fired when an article in the PageList is watched.\n\t\t */\n\t\tutil.repeatEvent( watchstar, this, 'unwatch' );\n\n\t\treturn watchstar;\n\t}\n} );\n\nmodule.exports = WatchstarPageList;\n","const\n\tmfExtend = require( '../mobile.startup/mfExtend' ),\n\tView = require( '../mobile.startup/View' ),\n\tPanel = require( '../mobile.startup/Panel' ),\n\tutil = require( '../mobile.startup/util' );\n\n/**\n * Create a panel with a child\n * @param {jQuery.Object} $child\n * @return {Panel}\n */\nfunction makePanel( $child ) {\n\tconst panel = new Panel();\n\tpanel.$el.append( $child );\n\treturn panel;\n}\n\n/**\n * Form for adding a talk section\n * @class AddTopicForm\n * @extends View\n *\n * @param {Object} options Configuration options\n * @param {string} options.licenseMsg license text (HTML strings accepted)\n * @param {Function} options.onTextInput callback for when text changes\n * @param {string} options.subject to prefill form with\n * @param {string} options.body to prefill form with\n * @param {boolean} options.disabled to mark the form inputs as disabled\n */\nfunction AddTopicForm( options ) {\n\tView.call( this,\n\t\tutil.extend( options, {\n\t\t\t// Template properties\n\t\t\ttopicTitlePlaceHolder: mw.msg( 'mobile-frontend-talk-add-overlay-subject-placeholder' ),\n\t\t\ttopicContentPlaceHolder: mw.msg( 'mobile-frontend-talk-add-overlay-content-placeholder' ),\n\n\t\t\t// Additional data\n\t\t\tclassName: 'add-topic-form',\n\t\t\tevents: {\n\t\t\t\t'input .wikitext-editor, input': 'onTextInput',\n\t\t\t\t'change .wikitext-editor, input': 'onTextInput'\n\t\t\t}\n\t\t} )\n\t);\n}\n\nmfExtend( AddTopicForm, View, {\n\t/**\n\t * @inheritdoc\n\t * @memberof AddTopicForm\n\t * @instance\n\t */\n\tpostRender: function () {\n\t\tconst options = this.options,\n\t\t\tdisabled = options.disabled,\n\t\t\t$subject = util.parseHTML( '<input>' ).attr( {\n\t\t\t\tclass: 'mw-ui-input',\n\t\t\t\ttype: 'text',\n\t\t\t\tdisabled,\n\t\t\t\tvalue: options.subject,\n\t\t\t\tplaceholder: options.topicTitlePlaceHolder\n\t\t\t} ),\n\t\t\t$body = util.parseHTML( '<textarea>' ).attr( {\n\t\t\t\tclass: 'wikitext-editor mw-ui-input',\n\t\t\t\tcols: 40,\n\t\t\t\trows: 10,\n\t\t\t\tdisabled,\n\t\t\t\tplaceholder: options.topicContentPlaceHolder\n\t\t\t} ).val( options.body ),\n\t\t\tpanels = [\n\t\t\t\tmakePanel( util.parseHTML( '<p>' ).addClass( 'license' ).html( options.licenseMsg ) ),\n\t\t\t\tmakePanel( $subject ),\n\t\t\t\tmakePanel( $body )\n\t\t\t];\n\n\t\tthis.$el.append(\n\t\t\tpanels.map( function ( panel ) {\n\t\t\t\treturn panel.$el;\n\t\t\t} )\n\t\t);\n\t\tthis.$subject = $subject;\n\t\tthis.$messageBody = $body;\n\t\tView.prototype.postRender.apply( this, arguments );\n\t},\n\t/**\n\t * Handles an input into a textarea and enables or disables the submit button\n\t * @memberof AddTopicForm\n\t * @instance\n\t */\n\tonTextInput: function () {\n\t\tif ( this.options.onTextInput ) {\n\t\t\tthis.options.onTextInput( this.$subject.val().trim(), this.$messageBody.val().trim() );\n\t\t}\n\t}\n} );\n\nAddTopicForm.test = {\n\tmakePanel\n};\n\nmodule.exports = AddTopicForm;\n","var\n\tmfExtend = require( '../mobile.startup/mfExtend' ),\n\tOverlay = require( '../mobile.startup/Overlay' ),\n\tPageGateway = require( '../mobile.startup/PageGateway' ),\n\tutil = require( '../mobile.startup/util' ),\n\tmakeAddTopicForm = require( './makeAddTopicForm' ),\n\ttoast = require( '../mobile.startup/toast' ),\n\tIcon = require( '../mobile.startup/Icon' );\n\n/**\n * Overlay for adding a talk section\n * @class TalkSectionAddOverlay\n * @extends Overlay\n * @uses Toast\n *\n * @param {Object} options Configuration options\n * @param {Object} options.title Title of the talk page being modified\n * @param {Object} options.currentPageTitle Title of the page before the overlay appears\n * @param {OO.EventEmitter} options.eventBus Object used to emit talk-added-wo-overlay\n * and talk-discussion-added events\n */\nfunction TalkSectionAddOverlay( options ) {\n\tthis.editorApi = options.api;\n\tthis.pageGateway = new PageGateway( options.api );\n\tOverlay.call( this,\n\t\tutil.extend( options, {\n\t\t\tclassName: 'talk-overlay overlay',\n\t\t\tevents: {\n\t\t\t\t'click .confirm-save': 'onSaveClick'\n\t\t\t}\n\t\t} )\n\t);\n\tthis.title = options.title;\n\tthis.currentPageTitle = options.currentPageTitle;\n\tthis.eventBus = options.eventBus;\n\t// Variable to indicate, if the overlay will be closed by the save function\n\t// or by the user. If this is false and there is content in the input fields,\n\t// the user will be asked, if he want to abandon his changes before we close\n\t// the Overlay, otherwise the Overlay will be closed without any question.\n\tthis._saveHit = false;\n}\n\nmfExtend( TalkSectionAddOverlay, Overlay, {\n\t/**\n\t * @memberof TalkSectionAddOverlay\n\t * @instance\n\t * @mixes Overlay#defaults\n\t * @property {Object} defaults Default options hash.\n\t * @property {string} defaults.cancelMsg Caption for cancel button on edit form.\n\t * @property {string} defaults.topicTitlePlaceHolder Placeholder text to prompt user to add\n\t * a talk page topic subject.\n\t * @property {string} defaults.topicContentPlaceHolder Placeholder text to prompt user\n\t *  to add content to talk page content.\n\t * @property {string} defaults.editingMsg Label for button which\n\t *  submits a new talk page topic.\n\t */\n\tdefaults: util.extend( {}, Overlay.prototype.defaults, {\n\t\tcancelMsg: mw.msg( 'mobile-frontend-editor-cancel' ),\n\t\teditingMsg: mw.msg( 'mobile-frontend-talk-add-overlay-submit' ),\n\t\twaitMsg: mw.msg( 'mobile-frontend-talk-topic-wait' ),\n\t\t// icons.spinner can't be used, .loading has a fixed height, which breaks overlay-header\n\t\twaitIcon: new Icon( {\n\t\t\tname: 'spinner',\n\t\t\tadditionalClassNames: 'savespinner loading'\n\t\t} ).toHtmlString()\n\t} ),\n\t/**\n\t * @inheritdoc\n\t * @memberof TalkSectionAddOverlay\n\t * @instance\n\t */\n\ttemplate: mw.template.get( 'mobile.talk.overlays', 'SectionAddOverlay.hogan' ),\n\t/**\n\t * @inheritdoc\n\t * @memberof TalkSectionAddOverlay\n\t * @instance\n\t */\n\ttemplatePartials: util.extend( {}, Overlay.prototype.templatePartials, {\n\t\tcontentHeader: mw.template.get( 'mobile.talk.overlays', 'SectionAddOverlay/contentHeader.hogan' ),\n\t\tsaveHeader: mw.template.get( 'mobile.editor.overlay', 'saveHeader.hogan' )\n\t} ),\n\t/**\n\t * @inheritdoc\n\t * @memberof TalkSectionAddOverlay\n\t * @instance\n\t */\n\tpostRender: function () {\n\t\tlet topicForm;\n\t\tOverlay.prototype.postRender.call( this );\n\t\ttopicForm = makeAddTopicForm( {\n\t\t\tsubject: '',\n\t\t\tbody: '',\n\t\t\tdisabled: false,\n\t\t\tlicenseMsg: this.options.licenseMsg,\n\t\t\tonTextInput: this.onTextInput.bind( this )\n\t\t} );\n\t\tthis.showHidden( '.initial-header' );\n\t\tthis.$confirm = this.$el.find( 'button.confirm-save' );\n\t\tthis.$el.find( '.overlay-content' ).append( topicForm.$el );\n\t\tthis.$subject = topicForm.$el.find( 'input' );\n\t\tthis.$ta = topicForm.$el.find( '.wikitext-editor' );\n\t},\n\t/**\n\t * @inheritdoc\n\t * @memberof TalkSectionAddOverlay\n\t * @instance\n\t */\n\thide: function () {\n\t\tvar empty,\n\t\t\tconfirmMessage = mw.msg( 'mobile-frontend-editor-cancel-confirm' );\n\n\t\tempty = ( !this.$subject.val() && !this.$ta.val() );\n\t\t// TODO: Replace with an OOUI dialog\n\t\tif ( this._saveHit || empty || window.confirm( confirmMessage ) ) {\n\t\t\treturn Overlay.prototype.hide.apply( this, arguments );\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t},\n\t/**\n\t * Handles an input into a textarea and enables or disables the submit button\n\t * @memberof TalkSectionAddOverlay\n\t * @param {string} subject\n\t * @param {string} body\n\t * @instance\n\t */\n\tonTextInput: function ( subject, body ) {\n\t\tthis.subject = subject;\n\t\tthis.body = body;\n\n\t\tclearTimeout( this.timer );\n\t\tthis.timer = setTimeout( function () {\n\t\t\tif ( !body || !subject ) {\n\t\t\t\tthis.$confirm.prop( 'disabled', true );\n\t\t\t} else {\n\t\t\t\tthis.$confirm.prop( 'disabled', false );\n\t\t\t}\n\t\t}.bind( this ), 250 );\n\t},\n\t/**\n\t * Handles a click on the save button\n\t * @memberof TalkSectionAddOverlay\n\t * @instance\n\t */\n\tonSaveClick: function () {\n\t\tvar isOnTalkPage = this.title === this.currentPageTitle;\n\n\t\tthis.showHidden( '.saving-header' );\n\t\tthis.save().then( function ( status ) {\n\t\t\tif ( status === 'ok' ) {\n\t\t\t\tif ( isOnTalkPage ) {\n\t\t\t\t\tthis.eventBus.emit( 'talk-added-wo-overlay' );\n\t\t\t\t} else {\n\t\t\t\t\tthis.pageGateway.invalidatePage( this.title );\n\t\t\t\t\ttoast.show( mw.msg( 'mobile-frontend-talk-topic-feedback' ) );\n\t\t\t\t\tthis.eventBus.emit( 'talk-discussion-added' );\n\t\t\t\t\tthis.hide();\n\t\t\t\t}\n\t\t\t}\n\t\t}.bind( this ), function ( error ) {\n\t\t\tvar editMsg = mw.msg( 'mobile-frontend-talk-topic-error' );\n\n\t\t\tthis.$confirm.prop( 'disabled', false );\n\t\t\tswitch ( error.details ) {\n\t\t\t\tcase 'protectedpage':\n\t\t\t\t\teditMsg = mw.msg( 'mobile-frontend-talk-topic-error-protected' );\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'noedit':\n\t\t\t\tcase 'blocked':\n\t\t\t\t\teditMsg = mw.msg( 'mobile-frontend-talk-topic-error-permission' );\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'spamdetected':\n\t\t\t\t\teditMsg = mw.msg( 'mobile-frontend-talk-topic-error-spam' );\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'badtoken':\n\t\t\t\t\teditMsg = mw.msg( 'mobile-frontend-talk-topic-error-badtoken' );\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\teditMsg = mw.msg( 'mobile-frontend-talk-topic-error' );\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\ttoast.show( editMsg, { type: 'error' } );\n\t\t\tthis.showHidden( '.save-header, .save-panel' );\n\t\t}.bind( this ) );\n\t},\n\t/**\n\t * Save new talk section\n\t * @memberof TalkSectionAddOverlay\n\t * @instance\n\t * @return {jQuery.Deferred} Object that either will be resolved with ok parameter\n\t * or rejected with type error.\n\t */\n\tsave: function () {\n\t\tvar heading = this.subject,\n\t\t\td = util.Deferred();\n\n\t\tthis.$ta.removeClass( 'error' );\n\t\tthis.$subject.removeClass( 'error' );\n\n\t\t// propagate, that we save an edit and want to close the Overlay without\n\t\t// any interruption (user questions e.g.)\n\t\tthis._saveHit = true;\n\n\t\tthis.$el.find( '.content' ).empty().addClass( 'loading' );\n\t\t// FIXME: while saving: a spinner would be nice\n\t\t// FIXME: This should be using a gateway e.g. TalkGateway, PageGateway or EditorGateway\n\t\treturn this.editorApi.postWithToken( 'csrf', {\n\t\t\taction: 'edit',\n\t\t\tsection: 'new',\n\t\t\tsectiontitle: heading,\n\t\t\ttitle: this.title,\n\t\t\tsummary: mw.msg( 'newsectionsummary', heading ),\n\t\t\ttext: this.body\n\t\t} ).then( function () {\n\t\t\treturn 'ok';\n\t\t}, function ( msg ) {\n\t\t\t// FIXME: Throw an Error\n\t\t\treturn d.reject( {\n\t\t\t\ttype: 'error',\n\t\t\t\tdetails: msg\n\t\t\t} );\n\t\t} );\n\t}\n} );\n\nmodule.exports = TalkSectionAddOverlay;\n","var\n\tuser = mw.user,\n\tmfExtend = require( '../mobile.startup/mfExtend' ),\n\tPageGateway = require( '../mobile.startup/PageGateway' ),\n\tOverlay = require( '../mobile.startup/Overlay' ),\n\tutil = require( '../mobile.startup/util' ),\n\tpopup = require( '../mobile.startup/toast' ),\n\tautosign = require( './autosign' ),\n\tPage = require( '../mobile.startup/Page' ),\n\tButton = require( '../mobile.startup/Button' );\n\n/**\n * Overlay for showing talk page section\n * @class TalkSectionOverlay\n * @extends Overlay\n * @uses PageGateway\n * @uses Page\n * @uses Button\n * @uses Toast\n * @param {Object} options\n */\nfunction TalkSectionOverlay( options ) {\n\tthis.editorApi = options.api;\n\tthis.pageGateway = new PageGateway( options.api );\n\tOverlay.call( this,\n\t\tutil.extend( true, options, {\n\t\t\tclassName: 'talk-overlay overlay',\n\t\t\tevents: {\n\t\t\t\t'focus textarea': 'onFocusTextarea',\n\t\t\t\t'click .save-button': 'onSaveClick'\n\t\t\t}\n\t\t} )\n\t);\n}\n\nmfExtend( TalkSectionOverlay, Overlay, {\n\ttemplatePartials: util.extend( {}, Overlay.prototype.templatePartials, {\n\t\theader: mw.template.get( 'mobile.talk.overlays', 'Section/header.hogan' ),\n\t\tcontent: mw.template.get( 'mobile.talk.overlays', 'Section/content.hogan' )\n\t} ),\n\t/**\n\t * @memberof TalkSectionOverlay\n\t * @instance\n\t * @mixes Overlay#defaults\n\t * @property {Object} defaults Default options hash.\n\t * @property {string} defaults.title Title.\n\t * @property {Section} defaults.section that is currently being viewed in overlay.\n\t * @property {string} defaults.reply Reply heading.\n\t * @property {string} defaults.info Message that informs the user their talk reply will be\n\t * automatically signed.\n\t */\n\tdefaults: util.extend( {}, Overlay.prototype.defaults, {\n\t\tsaveButton: new Button( {\n\t\t\tblock: true,\n\t\t\tadditionalClassNames: 'save-button',\n\t\t\tprogressive: true,\n\t\t\tlabel: mw.config.get( 'wgEditSubmitButtonLabelPublish' ) ?\n\t\t\t\tmw.msg( 'mobile-frontend-editor-publish' ) : mw.msg( 'mobile-frontend-editor-save' )\n\t\t} ).options,\n\t\ttitle: undefined,\n\t\tsection: undefined,\n\t\treply: mw.msg( 'mobile-frontend-talk-reply' ),\n\t\tinfo: mw.msg( 'mobile-frontend-talk-reply-info' )\n\t} ),\n\t/**\n\t * Fetches the talk topics of the page specified in options.title\n\t * if options.section is not defined.\n\t * @inheritdoc\n\t * @memberof TalkSectionOverlay\n\t * @instance\n\t */\n\tpostRender: function () {\n\t\tOverlay.prototype.postRender.apply( this );\n\t\tthis.$saveButton = this.$el.find( '.save-button' );\n\t\tif ( !this.options.section ) {\n\t\t\tthis.renderFromApi( this.options );\n\t\t} else {\n\t\t\tthis.hideSpinner();\n\t\t\tthis._enableComments();\n\t\t}\n\t},\n\t/**\n\t * Enables comments on the current rendered talk topic\n\t * @memberof TalkSectionOverlay\n\t * @instance\n\t * @private\n\t */\n\t_enableComments: function () {\n\t\tthis.$commentBox = this.$el.find( '.comment' );\n\t\tif ( user.isAnon() ) {\n\t\t\tthis.$commentBox.remove();\n\t\t} else {\n\t\t\tthis.$textarea = this.$commentBox.find( 'textarea' );\n\t\t}\n\t},\n\t/**\n\t * Loads the discussion from api and add it to the Overlay\n\t * @memberof TalkSectionOverlay\n\t * @instance\n\t * @param {Object} options Render options\n\t */\n\trenderFromApi: function ( options ) {\n\t\tvar self = this;\n\n\t\tthis.pageGateway.getPage( options.title ).then( function ( pageData ) {\n\t\t\tvar page = new Page( pageData );\n\t\t\toptions.section = page.getSection( options.id );\n\t\t\tself.render( options );\n\t\t\tself.hideSpinner();\n\t\t} );\n\t},\n\t/**\n\t * Handler for focus of textarea\n\t * @memberof TalkSectionOverlay\n\t * @instance\n\t */\n\tonFocusTextarea: function () {\n\t\tthis.$textarea.removeClass( 'error' );\n\t},\n\t/**\n\t * Handle a click on the save button\n\t * @memberof TalkSectionOverlay\n\t * @instance\n\t */\n\tonSaveClick: function () {\n\t\tvar val = this.$textarea.val(),\n\t\t\tself = this;\n\n\t\tfunction enableSaveButton() {\n\t\t\tself.$saveButton.prop( 'disabled', false );\n\t\t}\n\t\tif ( val ) {\n\t\t\t// show a spinner\n\t\t\tthis.showSpinner();\n\t\t\tthis.$saveButton.prop( 'disabled', true );\n\t\t\t// sign and add newline to front\n\t\t\tval = '\\n\\n' + autosign( val );\n\t\t\t// FIXME: This should be using a gateway\n\t\t\t// e.g. TalkGateway, PageGateway or EditorGateway\n\t\t\tthis.editorApi.postWithToken( 'csrf', {\n\t\t\t\taction: 'edit',\n\t\t\t\ttitle: this.options.title,\n\t\t\t\tsection: this.options.id,\n\t\t\t\tappendtext: val,\n\t\t\t\tredirect: true\n\t\t\t} ).then( function () {\n\t\t\t\tpopup.show( mw.msg( 'mobile-frontend-talk-reply-success' ) );\n\t\t\t\t// invalidate the cache\n\t\t\t\tself.pageGateway.invalidatePage( self.options.title );\n\n\t\t\t\tself.renderFromApi( self.options );\n\n\t\t\t\tenableSaveButton();\n\t\t\t}, function ( data, response ) {\n\t\t\t\t// FIXME: Code sharing with EditorOverlay?\n\t\t\t\tvar msg,\n\t\t\t\t\t// When save failed with one of these error codes, the returned\n\t\t\t\t\t// message in response.error.info will be forwarded to the user.\n\t\t\t\t\t// FIXME: This shouldn't be needed when info texts are all localized.\n\t\t\t\t\twhitelistedErrorInfo = [\n\t\t\t\t\t\t'readonly',\n\t\t\t\t\t\t'blocked',\n\t\t\t\t\t\t'autoblocked'\n\t\t\t\t\t];\n\n\t\t\t\tif (\n\t\t\t\t\tresponse.error &&\n\t\t\t\t\twhitelistedErrorInfo.indexOf( response.error.code ) > -1\n\t\t\t\t) {\n\t\t\t\t\tmsg = response.error.info;\n\t\t\t\t} else {\n\t\t\t\t\tmsg = mw.msg( 'mobile-frontend-editor-error' );\n\t\t\t\t}\n\n\t\t\t\tself.hideSpinner();\n\t\t\t\tpopup.show( msg, 'toast error' );\n\n\t\t\t\tenableSaveButton();\n\t\t\t} );\n\t\t} else {\n\t\t\tthis.$textarea.addClass( 'error' );\n\t\t}\n\t}\n} );\n\nmodule.exports = TalkSectionOverlay;\n","/**\n * Autosign a block of text if necessary\n * @instance\n * @param {string} text\n * @return {string} text with an autosign (\"~~~~\") if necessary\n */\nfunction autosign( text ) {\n\treturn /~{3,5}/.test( text ) ? text : text + ' ~~~~';\n}\n\nmodule.exports = autosign;\n","const AddTopicForm = require( './AddTopicForm' ),\n\tautosign = require( './autosign' );\n\n/**\n * Backwards compatible method for obtaining a TalkOverlay\n * used by Minerva until it updates itself.\n * @deprecated\n * @param {Object} options Configuration options\n * @param {string} options.licenseMsg license text (HTML strings accepted)\n * @param {Function} [options.onTextInput] callback for when text changes\n * @param {string} options.subject to prefill form with\n * @param {string} options.body to prefill form with\n * @param {boolean} options.disabled to mark the form inputs as disabled\n * @return {AddTopicForm}\n */\nfunction makeAddTopicForm( { licenseMsg, onTextInput, subject, body, disabled } ) {\n\tconst form = new AddTopicForm( {\n\t\tlicenseMsg,\n\t\tdisabled,\n\t\tsubject,\n\t\tbody,\n\t\tonTextInput: onTextInput ? function ( subject, body ) {\n\t\t\t// if the body has content, autosign it!\n\t\t\tif ( body ) {\n\t\t\t\tbody = autosign( body );\n\t\t\t}\n\t\t\t// propagate up the autosigned content\n\t\t\tonTextInput.call( this, subject, body );\n\t\t} : undefined\n\t} );\n\treturn form;\n}\n\nmodule.exports = makeAddTopicForm;\n","var util = require( '../mobile.startup/util' ),\n\tView = require( '../mobile.startup/View' );\n\n/**\n * A board of talk topics\n * @param {Section[]} sections\n * @return {View}\n */\nfunction talkBoard( sections ) {\n\tvar board,\n\t\texplanation = sections.length > 0 ?\n\t\t\tmw.msg( 'mobile-frontend-talk-explained' ) :\n\t\t\tmw.msg( 'mobile-frontend-talk-explained-empty' );\n\n\tboard = new View( {\n\t\tclassName: 'talk-board'\n\t} );\n\tboard.append( [\n\t\tutil.parseHTML( '<p class=\"content-header\">' ).text( explanation ),\n\t\t// FIXME: Substitute with a TopicTitleList (T173534)\n\t\tutil.parseHTML( '<ul class=\"topic-title-list\">' ).append(\n\t\t\tsections.map( function ( section ) {\n\t\t\t\treturn util.parseHTML( '<li>' ).append(\n\t\t\t\t\tutil.parseHTML( '<a>' )\n\t\t\t\t\t\t.attr( 'href', '#/talk/' + section.id )\n\t\t\t\t\t\t.text( section.line )\n\t\t\t\t);\n\t\t\t} )\n\t\t)\n\t] );\n\treturn board;\n}\n\nmodule.exports = talkBoard;\n","var\n\tutil,\n\tCategoryGateway,\n\tsandbox,\n\tjQuery = require( '../utils/jQuery' ),\n\tdom = require( '../utils/dom' ),\n\tmediaWiki = require( '../utils/mw' ),\n\too = require( '../utils/oo' ),\n\tsinon = require( 'sinon' );\n\nQUnit.module( 'MobileFrontend CategoryGateway.js', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\too.setUp( sandbox, global );\n\t\tmediaWiki.setUp( sandbox, global );\n\n\t\tutil = require( '../../../src/mobile.startup/util' );\n\t\tCategoryGateway = require( '../../../src/mobile.categories.overlays/CategoryGateway' );\n\n\t\tthis.getSpy = {\n\t\t\tget: sandbox.stub().returns( util.Deferred().resolve( {\n\t\t\t\tbatchcomplete: true,\n\t\t\t\tquery: {\n\t\t\t\t\tpages: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tpageid: 5,\n\t\t\t\t\t\t\tns: 0,\n\t\t\t\t\t\t\ttitle: 'HelloWorld',\n\t\t\t\t\t\t\tcategories: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tns: 14,\n\t\t\t\t\t\t\t\t\ttitle: 'Category:Hello'\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t} ) )\n\t\t};\n\t\tthis.postSpy = {\n\t\t\tpostWithToken: sandbox.stub().returns( util.Deferred().resolve() )\n\t\t};\n\t},\n\tafterEach: function () {\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( 'getCategories()', function ( assert ) {\n\tvar\n\t\tself = this,\n\t\tresult,\n\t\tgateway = new CategoryGateway( this.getSpy );\n\n\tresult = gateway.getCategories( 'HelloWorld' );\n\tassert.notStrictEqual( result, false, 'result should not return false' );\n\n\treturn result.then( function () {\n\t\tassert.strictEqual( gateway.canContinue, false, 'gateway should not continue' );\n\t\tassert.ok( self.getSpy.get.calledWith( {\n\t\t\taction: 'query',\n\t\t\tprop: 'categories',\n\t\t\ttitles: 'HelloWorld',\n\t\t\tclprop: 'hidden',\n\t\t\tcllimit: 50,\n\t\t\tformatversion: 2\n\t\t} ), 'invalid data passed to get api request' );\n\t} );\n\n} );\n\nQUnit.test( 'save()', function ( assert ) {\n\tvar\n\t\tself = this,\n\t\tgateway = new CategoryGateway( this.postSpy ),\n\t\ttitle = 'HelloWorld',\n\t\tcategories = '[[Category:World]]';\n\n\treturn gateway.save( title, categories ).then( function () {\n\t\tassert.ok( self.postSpy.postWithToken.calledWith( 'csrf', {\n\t\t\taction: 'edit',\n\t\t\ttitle: title,\n\t\t\tappendtext: categories,\n\t\t\tsummary: mw.msg( 'mobile-frontend-categories-summary' )\n\t\t} ), 'invalid data passed to post api request' );\n\t} );\n} );\n","var sandbox, EditorGateway, spy, postStub, apiReject, apiHappy, apiRvNoSection,\n\tapiCaptchaFail, apiAbuseFilterDisallow, apiAbuseFilterWarning, apiAbuseFilterOther,\n\tapiTestError, apiReadOnly, apiExpiredToken, apiWithSectionLine, apiHappyTestContent,\n\tapiEmptySuccessResponse, apiNoSectionLine, apiRejectHttp,\n\tutil = require( '../../../src/mobile.startup/util' ),\n\thappyResponse,\n\tcaptcha = {\n\t\ttype: 'image',\n\t\tmime: 'image/png',\n\t\tid: '1852528679',\n\t\turl: '/w/index.php?title=Especial:Captcha/image&wpCaptchaId=1852528679'\n\t},\n\tapiReadOnlyResponse = {\n\t\terror: {\n\t\t\tcode: 'readonly',\n\t\t\tinfo: 'The wiki is currently in read-only mode.',\n\t\t\treadonlyreason: 'This wiki is currently being upgraded to a newer software version.'\n\t\t}\n\t},\n\tjQuery = require( '../utils/jQuery' ),\n\tdom = require( '../utils/dom' ),\n\tsinon = require( 'sinon' ),\n\too = require( '../utils/oo' ),\n\tmediaWiki = require( '../utils/mw' );\n\nQUnit.module( 'MobileFrontend mobile.editor.overlay/EditorGateway', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\too.setUp( sandbox, global );\n\t\tmediaWiki.setUp( sandbox, global );\n\t\tEditorGateway = require( '../../../src/mobile.editor.overlay/EditorGateway' );\n\t\thappyResponse = util.Deferred().resolve( {\n\t\t\tquery: {\n\t\t\t\tpages: [\n\t\t\t\t\t{\n\t\t\t\t\t\trevisions: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttimestamp: '2013-05-15T00:30:26Z',\n\t\t\t\t\t\t\t\tcontent: 'section'\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t]\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\tuserinfo: {\n\t\t\t\t\tid: 0\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t\tapiHappy = new mw.Api();\n\t\tapiReject = new mw.Api();\n\t\tapiRvNoSection = new mw.Api();\n\t\tapiCaptchaFail = new mw.Api();\n\t\tapiAbuseFilterDisallow = new mw.Api();\n\t\tapiAbuseFilterWarning = new mw.Api();\n\t\tapiAbuseFilterOther = new mw.Api();\n\t\tapiTestError = new mw.Api();\n\t\tapiReadOnly = new mw.Api();\n\t\tapiExpiredToken = new mw.Api();\n\t\tapiWithSectionLine = new mw.Api();\n\t\tapiHappyTestContent = new mw.Api();\n\t\tapiRejectHttp = new mw.Api();\n\t\tapiEmptySuccessResponse = new mw.Api();\n\t\tapiNoSectionLine = new mw.Api();\n\t\tsandbox.stub( apiCaptchaFail, 'postWithToken' ).returns(\n\t\t\tutil.Deferred().resolve( {\n\t\t\t\tedit: {\n\t\t\t\t\tresult: 'Failure',\n\t\t\t\t\tcaptcha: captcha\n\t\t\t\t}\n\t\t\t} )\n\t\t);\n\t\tspy = sandbox.stub( apiHappy, 'get' ).returns( happyResponse );\n\t\tsandbox.stub( apiReject, 'get' ).returns( happyResponse );\n\t\tsandbox.stub( apiRejectHttp, 'get' ).returns( happyResponse );\n\t\tsandbox.stub( apiHappyTestContent, 'get' ).returns( happyResponse );\n\t\tsandbox.stub( apiEmptySuccessResponse, 'get' ).returns( happyResponse );\n\t\tsandbox.stub( apiAbuseFilterDisallow, 'get' ).returns( happyResponse );\n\t\tsandbox.stub( apiAbuseFilterOther, 'get' ).returns( happyResponse );\n\t\tsandbox.stub( apiTestError, 'get' ).returns( happyResponse );\n\t\tsandbox.stub( apiExpiredToken, 'get' ).returns( happyResponse );\n\t\tsandbox.stub( apiWithSectionLine, 'get' ).returns( happyResponse );\n\t\tsandbox.stub( apiReadOnly, 'get' ).returns( happyResponse );\n\t\tsandbox.stub( apiAbuseFilterWarning, 'get' ).returns( happyResponse );\n\t\tsandbox.stub( apiCaptchaFail, 'get' ).returns( happyResponse );\n\t\tsandbox.stub( apiRvNoSection, 'get' ).returns(\n\t\t\tutil.Deferred().resolve( {\n\t\t\t\terror: {\n\t\t\t\t\tcode: 'rvnosuchsection'\n\t\t\t\t}\n\t\t\t} )\n\t\t);\n\t\tsandbox.stub( apiReject, 'postWithToken' ).returns( util.Deferred().resolve(\n\t\t\t{\n\t\t\t\terror: {\n\t\t\t\t\tcode: 'error code'\n\t\t\t\t}\n\t\t\t}\n\t\t) );\n\t\tsandbox.stub( apiRejectHttp, 'postWithToken' ).returns( util.Deferred().reject() );\n\t\tpostStub = sandbox.stub( apiHappy, 'postWithToken' ).returns(\n\t\t\tutil.Deferred().resolve( {\n\t\t\t\tedit: {\n\t\t\t\t\tresult: 'Success'\n\t\t\t\t}\n\t\t\t} )\n\t\t);\n\t\tsandbox.stub( apiEmptySuccessResponse, 'postWithToken' ).returns( util.Deferred().resolve( {} ) );\n\t\tsandbox.stub( apiHappyTestContent, 'post' ).returns( util.Deferred().resolve( {\n\t\t\tparse: {\n\t\t\t\ttitle: 'test',\n\t\t\t\ttext: {\n\t\t\t\t\t'*': '<h1>Heading 1</h1><h2>Heading 2</h2><p>test content</p>'\n\t\t\t\t},\n\t\t\t\tsections: {}\n\t\t\t}\n\t\t} ) );\n\t\tsandbox.stub( apiNoSectionLine, 'post' ).returns( util.Deferred().resolve( {\n\t\t\tparse: {\n\t\t\t\ttitle: 'test',\n\t\t\t\ttext: {\n\t\t\t\t\t'*': 'test content'\n\t\t\t\t},\n\t\t\t\tsections: {}\n\t\t\t}\n\t\t} ) );\n\t\tsandbox.stub( apiWithSectionLine, 'post' ).returns( util.Deferred().resolve( {\n\t\t\tparse: {\n\t\t\t\ttitle: 'test',\n\t\t\t\ttext: {\n\t\t\t\t\t'*': 'test content'\n\t\t\t\t},\n\t\t\t\tsections: {\n\t\t\t\t\t0: {\n\t\t\t\t\t\tline: 'Test section',\n\t\t\t\t\t\tanchor: 'Test_section'\n\t\t\t\t\t},\n\t\t\t\t\t1: {\n\t\t\t\t\t\tline: 'Test section2',\n\t\t\t\t\t\tanchor: 'Test_section2'\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} ) );\n\t\tsandbox.stub( apiExpiredToken, 'postWithToken' )\n\t\t\t.onFirstCall().returns( util.Deferred().resolve( {\n\t\t\t\tedit: {\n\t\t\t\t\tresult: 'Success'\n\t\t\t\t}\n\t\t\t} ) );\n\t\tsandbox.stub( apiAbuseFilterWarning, 'postWithToken' ).returns(\n\t\t\tutil.Deferred().resolve( {\n\t\t\t\tedit: {\n\t\t\t\t\tcode: 'abusefilter-warning-usuwanie-tekstu',\n\t\t\t\t\tinfo: 'Hit AbuseFilter: Usuwanie du\\u017cej ilo\\u015bci tekstu',\n\t\t\t\t\twarning: 'horrible desktop-formatted message',\n\t\t\t\t\tresult: 'Failure'\n\t\t\t\t}\n\t\t\t} )\n\t\t);\n\t\tsandbox.stub( apiAbuseFilterDisallow, 'postWithToken' ).returns(\n\t\t\tutil.Deferred().resolve( {\n\t\t\t\tedit: {\n\t\t\t\t\tcode: 'abusefilter-disallow',\n\t\t\t\t\tinfo: 'Scary filter',\n\t\t\t\t\twarning: 'horrible desktop-formatted message',\n\t\t\t\t\tresult: 'Failure'\n\t\t\t\t}\n\t\t\t} )\n\t\t);\n\t\tsandbox.stub( apiAbuseFilterOther, 'postWithToken' ).returns(\n\t\t\tutil.Deferred().resolve( {\n\t\t\t\tedit: {\n\t\t\t\t\tcode: 'abusefilter-something',\n\t\t\t\t\tinfo: 'Scary filter',\n\t\t\t\t\twarning: 'horrible desktop-formatted message',\n\t\t\t\t\tresult: 'Failure'\n\t\t\t\t}\n\t\t\t} )\n\t\t);\n\t\tsandbox.stub( apiTestError, 'postWithToken' ).returns(\n\t\t\tutil.Deferred().resolve( {\n\t\t\t\tedit: {\n\t\t\t\t\tcode: 'testerror',\n\t\t\t\t\tresult: 'Failure'\n\t\t\t\t}\n\t\t\t} )\n\t\t);\n\t\tsandbox.stub( apiReadOnly, 'postWithToken' ).returns( util.Deferred().reject( 'readonly', apiReadOnlyResponse ) );\n\t},\n\tafterEach: function () {\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( '#getContent (no section)', function ( assert ) {\n\tvar gateway = new EditorGateway( {\n\t\tapi: apiHappy,\n\t\ttitle: 'MediaWiki:Test.css'\n\t} );\n\n\treturn gateway.getContent().then( function () {\n\t\tassert.ok( spy.calledWith( {\n\t\t\taction: 'query',\n\t\t\tprop: [ 'revisions', 'info' ],\n\t\t\tmeta: 'userinfo',\n\t\t\trvprop: [ 'content', 'timestamp' ],\n\t\t\ttitles: 'MediaWiki:Test.css',\n\t\t\tintestactions: 'edit',\n\t\t\tintestactionsdetail: 'full',\n\t\t\tuiprop: 'options',\n\t\t\tformatversion: 2\n\t\t} ), 'rvsection not passed to api request' );\n\t} );\n} );\n\nQUnit.test( '#getContent', function ( assert ) {\n\tvar gateway;\n\n\tgateway = new EditorGateway( {\n\t\tapi: apiHappy,\n\t\ttitle: 'test',\n\t\tsectionId: 1\n\t} );\n\n\treturn gateway.getContent().then( function ( resp ) {\n\t\tassert.strictEqual( resp.text, 'section', 'return section content' );\n\t\tassert.strictEqual( resp.blockinfo, null );\n\t\treturn gateway.getContent();\n\t} ).then( function () {\n\t\tassert.strictEqual( spy.callCount, 1, 'cache content' );\n\t} );\n} );\n\nQUnit.test( '#getContent, new page', function ( assert ) {\n\tvar gateway = new EditorGateway( {\n\t\tapi: apiHappy,\n\t\ttitle: 'test',\n\t\tisNewPage: true\n\t} );\n\n\treturn gateway.getContent().then( function ( resp ) {\n\t\tassert.strictEqual( resp.text, '', 'return empty section' );\n\t\tassert.strictEqual( resp.blockinfo, undefined );\n\t\tassert.notOk( spy.called, 'don\\'t try to retrieve content using API' );\n\t} );\n} );\n\nQUnit.test( '#getContent, missing section', function ( assert ) {\n\tvar gateway = new EditorGateway( {\n\t\tapi: apiRvNoSection,\n\t\ttitle: 'test',\n\t\tsectionId: 1\n\t} );\n\n\tassert.rejects( gateway.getContent(), /^rvnosuchsection$/, 'return error code' );\n} );\n\nQUnit.test( '#getBlockInfo', function ( assert ) {\n\tvar gateway = new EditorGateway( {\n\t\t\tapi: apiHappy,\n\t\t\ttitle: 'test'\n\t\t} ),\n\t\tblockinfo = {\n\t\t\tblockedby: 'Test'\n\t\t},\n\t\tpageObj = {\n\t\t\trevisions: [\n\t\t\t\t{}\n\t\t\t],\n\t\t\tactions: {\n\t\t\t\tedit: [\n\t\t\t\t\t{\n\t\t\t\t\t\tcode: 'blocked',\n\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\tblockinfo: blockinfo\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t};\n\n\tassert.strictEqual( blockinfo, gateway.getBlockInfo( pageObj ) );\n} );\n\nQUnit.test( '#save, success', function ( assert ) {\n\tvar gateway = new EditorGateway( {\n\t\tapi: apiHappy,\n\t\ttitle: 'test',\n\t\tsectionId: 1\n\t} );\n\n\treturn gateway.getContent().then( function () {\n\t\tgateway.setContent( 'section 1' );\n\t\tassert.strictEqual( gateway.hasChanged, true, 'hasChanged is true' );\n\t\treturn gateway.save( {\n\t\t\tsummary: 'summary'\n\t\t} );\n\t} ).then( function () {\n\t\tassert.strictEqual( gateway.hasChanged, false, 'reset hasChanged' );\n\t\tassert.ok( postStub.calledWith( 'csrf', {\n\t\t\taction: 'edit',\n\t\t\ttitle: 'test',\n\t\t\tsection: 1,\n\t\t\ttext: 'section 1',\n\t\t\tsummary: 'summary',\n\t\t\tcaptchaid: undefined,\n\t\t\tcaptchaword: undefined,\n\t\t\tbasetimestamp: '2013-05-15T00:30:26Z',\n\t\t\tstarttimestamp: '2013-05-15T00:30:26Z'\n\t\t} ), 'save first section' );\n\t} );\n} );\n\nQUnit.test( '#save, new page', function ( assert ) {\n\tvar gateway = new EditorGateway( {\n\t\tapi: apiHappy,\n\t\ttitle: 'Talk:test',\n\t\tisNewPage: true\n\t} );\n\n\tgateway.getContent();\n\tgateway.setContent( 'section 0' );\n\treturn gateway.save( {\n\t\tsummary: 'summary'\n\t} ).then( function () {\n\t\tassert.strictEqual( gateway.hasChanged, false, 'reset hasChanged' );\n\t\tassert.ok( postStub.calledWith( 'csrf', {\n\t\t\taction: 'edit',\n\t\t\ttitle: 'Talk:test',\n\t\t\ttext: 'section 0',\n\t\t\tsummary: 'summary',\n\t\t\tcaptchaid: undefined,\n\t\t\tcaptchaword: undefined,\n\t\t\tbasetimestamp: undefined,\n\t\t\tstarttimestamp: undefined\n\t\t} ), 'save lead section' );\n\t} );\n} );\n\nQUnit.test( '#save, after #setPrependText', function ( assert ) {\n\tvar gateway = new EditorGateway( {\n\t\tapi: apiHappy,\n\t\ttitle: 'test'\n\t} );\n\n\tgateway.setPrependText( 'abc' );\n\treturn gateway.save( {\n\t\tsummary: 'summary'\n\t} ).then( function () {\n\t\tassert.strictEqual( gateway.hasChanged, false, 'reset hasChanged' );\n\t\tassert.ok( postStub.calledWith( 'csrf', {\n\t\t\taction: 'edit',\n\t\t\ttitle: 'test',\n\t\t\tprependtext: 'abc',\n\t\t\tsummary: 'summary',\n\t\t\tcaptchaid: undefined,\n\t\t\tcaptchaword: undefined,\n\t\t\tbasetimestamp: undefined,\n\t\t\tstarttimestamp: undefined\n\t\t} ), 'prepend text' );\n\t} );\n} );\n\nQUnit.test( '#save, submit CAPTCHA', function ( assert ) {\n\tvar gateway = new EditorGateway( {\n\t\tapi: apiHappy,\n\t\ttitle: 'test',\n\t\tsectionId: 1\n\t} );\n\n\treturn gateway.getContent().then( function () {\n\t\tgateway.setContent( 'section 1' );\n\t} ).then( function () {\n\t\treturn gateway.save( {\n\t\t\tsummary: 'summary',\n\t\t\tcaptchaId: 123,\n\t\t\tcaptchaWord: 'abc'\n\t\t} );\n\t} ).then( function () {\n\t\tassert.strictEqual( gateway.hasChanged, false, 'reset hasChanged' );\n\t\tassert.ok( postStub.calledWith( 'csrf', {\n\t\t\taction: 'edit',\n\t\t\ttitle: 'test',\n\t\t\tsection: 1,\n\t\t\ttext: 'section 1',\n\t\t\tsummary: 'summary',\n\t\t\tcaptchaid: 123,\n\t\t\tcaptchaword: 'abc',\n\t\t\tbasetimestamp: '2013-05-15T00:30:26Z',\n\t\t\tstarttimestamp: '2013-05-15T00:30:26Z'\n\t\t} ), 'save first section' );\n\t} );\n} );\n\nQUnit.test( '#save, request failure', function ( assert ) {\n\tvar gateway = new EditorGateway( {\n\t\tapi: apiRejectHttp,\n\t\ttitle: 'test',\n\t\tsectionId: 1\n\t} );\n\n\treturn gateway.getContent().then( function () {\n\t\tgateway.setContent( 'section 1' );\n\t\tassert.rejects( gateway.save(), function ( given ) {\n\t\t\tassert.propEqual( given, {\n\t\t\t\ttype: 'error',\n\t\t\t\tdetails: 'http'\n\t\t\t}, 'called with correct arguments' );\n\n\t\t\treturn true;\n\t\t}, 'call fail' );\n\t} );\n} );\n\nQUnit.test( '#save, API failure', function ( assert ) {\n\tvar gateway = new EditorGateway( {\n\t\tapi: apiReject,\n\t\ttitle: 'test',\n\t\tsectionId: 1\n\t} );\n\n\treturn gateway.getContent().then( function () {\n\t\tgateway.setContent( 'section 1' );\n\t\tassert.rejects( gateway.save(), function ( given ) {\n\t\t\tassert.propEqual( given, {\n\t\t\t\ttype: 'error',\n\t\t\t\tdetails: 'error code'\n\t\t\t}, 'called with correct arguments' );\n\n\t\t\treturn true;\n\t\t}, 'call fail' );\n\t} );\n} );\n\nQUnit.test( '#save, CAPTCHA response with image URL', function ( assert ) {\n\tvar gateway = new EditorGateway( {\n\t\tapi: apiCaptchaFail,\n\t\ttitle: 'test',\n\t\tsectionId: 1\n\t} );\n\n\treturn gateway.getContent().then( function () {\n\t\tgateway.setContent( 'section 1' );\n\t\tassert.rejects( gateway.save(), function ( given ) {\n\t\t\tassert.propEqual( given, {\n\t\t\t\ttype: 'captcha',\n\t\t\t\tdetails: captcha\n\t\t\t}, 'called with correct arguments' );\n\n\t\t\treturn true;\n\t\t}, 'call fail' );\n\t} );\n} );\n\nQUnit.test( '#save, AbuseFilter warning', function ( assert ) {\n\tvar gateway = new EditorGateway( {\n\t\tapi: apiAbuseFilterWarning,\n\t\ttitle: 'test',\n\t\tsectionId: 1\n\t} );\n\n\treturn gateway.getContent().then( function () {\n\t\tgateway.setContent( 'section 1' );\n\n\t\tassert.rejects( gateway.save(), function ( given ) {\n\t\t\tassert.propEqual( given, {\n\t\t\t\ttype: 'abusefilter',\n\t\t\t\tdetails: {\n\t\t\t\t\ttype: 'warning',\n\t\t\t\t\tmessage: 'horrible desktop-formatted message'\n\t\t\t\t}\n\t\t\t}, 'called with correct arguments' );\n\n\t\t\treturn true;\n\t\t}, 'call fail' );\n\t} );\n} );\n\nQUnit.test( '#save, AbuseFilter disallow', function ( assert ) {\n\tvar gateway = new EditorGateway( {\n\t\tapi: apiAbuseFilterDisallow,\n\t\ttitle: 'test',\n\t\tsectionId: 1\n\t} );\n\n\treturn gateway.getContent().then( function () {\n\t\tgateway.setContent( 'section 1' );\n\n\t\tassert.rejects( gateway.save(), function ( given ) {\n\t\t\tassert.propEqual( given, {\n\t\t\t\ttype: 'abusefilter',\n\t\t\t\tdetails: {\n\t\t\t\t\ttype: 'disallow',\n\t\t\t\t\tmessage: 'horrible desktop-formatted message'\n\t\t\t\t}\n\t\t\t}, 'called with correct arguments' );\n\n\t\t\treturn true;\n\t\t}, 'call fail' );\n\t} );\n} );\n\nQUnit.test( '#save, AbuseFilter other', function ( assert ) {\n\tvar gateway = new EditorGateway( {\n\t\tapi: apiAbuseFilterOther,\n\t\ttitle: 'test',\n\t\tsectionId: 1\n\t} );\n\n\treturn gateway.getContent().then( function () {\n\t\tgateway.setContent( 'section 1' );\n\n\t\tassert.rejects( gateway.save(), function ( given ) {\n\t\t\tassert.propEqual( given, {\n\t\t\t\ttype: 'abusefilter',\n\t\t\t\tdetails: {\n\t\t\t\t\ttype: 'other',\n\t\t\t\t\tmessage: 'horrible desktop-formatted message'\n\t\t\t\t}\n\t\t\t}, 'called with correct arguments' );\n\n\t\t\treturn true;\n\t\t}, 'call fail' );\n\t} );\n} );\n\nQUnit.test( '#save, extension errors', function ( assert ) {\n\tvar gateway = new EditorGateway( {\n\t\tapi: apiTestError,\n\t\ttitle: 'test',\n\t\tsectionId: 1\n\t} );\n\n\treturn gateway.getContent().then( function () {\n\t\tgateway.setContent( 'section 1' );\n\n\t\tassert.rejects( gateway.save(), function ( given ) {\n\t\t\tassert.propEqual( given, {\n\t\t\t\ttype: 'error',\n\t\t\t\tdetails: 'testerror'\n\t\t\t}, 'called with correct arguments' );\n\n\t\t\treturn true;\n\t\t}, 'call fail' );\n\t} );\n} );\nQUnit.test( '#save, read-only error', function ( assert ) {\n\tvar gateway = new EditorGateway( {\n\t\t\tapi: apiReadOnly,\n\t\t\ttitle: 'test',\n\t\t\tsectionId: 1\n\t\t} ),\n\t\tresolveSpy = sandbox.spy(),\n\t\trejectSpy = sandbox.spy(),\n\t\tdone = assert.async(),\n\t\texpectedReturnValue = {\n\t\t\ttype: 'readonly',\n\t\t\tdetails: {\n\t\t\t\tcode: 'readonly',\n\t\t\t\tinfo: 'The wiki is currently in read-only mode.',\n\t\t\t\treadonlyreason: 'This wiki is currently being upgraded to a newer software version.'\n\t\t\t}\n\t\t};\n\n\tgateway.getContent().then( function () {\n\t\tgateway.setContent( 'section 1' );\n\t\treturn gateway.save();\n\t} ).then( resolveSpy, rejectSpy ).then( function () {\n\t\tassert.strictEqual( rejectSpy.calledWith( expectedReturnValue ), true );\n\t\tassert.strictEqual( resolveSpy.called, false, 'don\\'t call resolve' );\n\t\tdone();\n\t} );\n\n} );\n\nQUnit.test( '#save, unknown errors', function ( assert ) {\n\tvar gateway = new EditorGateway( {\n\t\tapi: apiEmptySuccessResponse,\n\t\ttitle: 'test',\n\t\tsectionId: 1\n\t} );\n\n\treturn gateway.getContent().then( function () {\n\t\tgateway.setContent( 'section 1' );\n\n\t\tassert.rejects( gateway.save(), function ( given ) {\n\t\t\tassert.propEqual( given, {\n\t\t\t\ttype: 'error',\n\t\t\t\tdetails: 'unknown'\n\t\t\t}, 'called with correct arguments' );\n\n\t\t\treturn true;\n\t\t}, 'call fail' );\n\t} );\n} );\n\nQUnit.test( '#save, without changes', function ( assert ) {\n\tvar gateway = new EditorGateway( {\n\t\tapi: apiHappy,\n\t\ttitle: 'test',\n\t\tsectionId: 1\n\t} );\n\n\treturn gateway.getContent().then( function () {\n\t\treturn gateway.setContent( 'section' );\n\t} ).then( function () {\n\t\tassert.strictEqual( gateway.hasChanged, false, 'hasChanged is false' );\n\t\treturn gateway.save( {\n\t\t\tsummary: 'summary'\n\t\t} );\n\t} ).then( function () {\n\t\tassert.ok( apiHappy.postWithToken.calledWith( 'csrf', {\n\t\t\taction: 'edit',\n\t\t\ttitle: 'test',\n\t\t\tsection: 1,\n\t\t\ttext: 'section',\n\t\t\tsummary: 'summary',\n\t\t\tcaptchaid: undefined,\n\t\t\tcaptchaword: undefined,\n\t\t\tbasetimestamp: '2013-05-15T00:30:26Z',\n\t\t\tstarttimestamp: '2013-05-15T00:30:26Z'\n\t\t} ), 'save first section' );\n\t} );\n} );\n\nQUnit.test( '#EditorGateway', function ( assert ) {\n\tvar gateway = new EditorGateway( {\n\t\t\tapi: apiHappyTestContent,\n\t\t\ttitle: 'Test',\n\t\t\tsectionId: 1\n\t\t} ),\n\t\tresolveSpy = sandbox.spy();\n\n\treturn gateway.getPreview( { text: 'test content' } )\n\t\t.then( resolveSpy )\n\t\t.then( function () {\n\t\t\tassert.ok( apiHappyTestContent.post.calledWithMatch( {\n\t\t\t\ttext: 'test content'\n\t\t\t} ) );\n\t\t\tassert.ok( resolveSpy.calledWith( {\n\t\t\t\tline: '',\n\t\t\t\tid: '',\n\t\t\t\ttext: '<h1>Heading 1</h1><h2>Heading 2</h2><p>test content</p>'\n\t\t\t} ) );\n\t\t} );\n\n} );\n\nQUnit.test( '#EditorGateway, check without sectionLine', function ( assert ) {\n\tvar gateway = new EditorGateway( {\n\t\tapi: apiNoSectionLine,\n\t\ttitle: 'Test',\n\t\tsectionId: 1\n\t} );\n\n\treturn gateway.getPreview( {\n\t\ttext: 'test content'\n\t} ).then( function ( section ) {\n\t\tassert.strictEqual( section.line, '', 'Ok, no section line returned' );\n\t} );\n} );\n\nQUnit.test( '#EditorGateway, check with sectionLine', function ( assert ) {\n\tvar gateway = new EditorGateway( {\n\t\tapi: apiWithSectionLine,\n\t\ttitle: 'Test',\n\t\tsectionId: 1\n\t} );\n\n\treturn gateway.getPreview( {\n\t\ttext: 'test content'\n\t} ).then( function ( section ) {\n\t\tassert.strictEqual( section.line, 'Test section', 'Ok, section line returned' );\n\t\tassert.strictEqual( section.id, 'Test_section', 'Ok, section ID returned' );\n\t} );\n} );\n\nQUnit.test( '#save, when token has expired', function ( assert ) {\n\tvar gateway = new EditorGateway( {\n\t\tapi: apiExpiredToken,\n\t\ttitle: 'MediaWiki:Test.css'\n\t} );\n\n\treturn gateway.getContent().then( function () {\n\t\tgateway.setContent( 'section 1' );\n\n\t\treturn gateway.save().then( function () {\n\t\t\tassert.strictEqual( apiExpiredToken.postWithToken.callCount, 1, 'check the spy was called twice' );\n\t\t} );\n\t} );\n} );\n","var sandbox, messageStub, getContentStub, previewResolve,\n\ttestUrl = '/w/index.php?title=User:Test',\n\tEditorGateway, EditorOverlay, BlockMessage,\n\tjQuery = require( '../utils/jQuery' ),\n\tsinon = require( 'sinon' ),\n\tutil = require( '../../../src/mobile.startup/util' ),\n\too = require( '../utils/oo' ),\n\tdom = require( '../utils/dom' ),\n\tmediaWiki = require( '../utils/mw' );\n\nQUnit.module( 'MobileFrontend mobile.editor.overlay/EditorOverlay', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\tmediaWiki.setUp( sandbox, global );\n\t\too.setUp( sandbox, global );\n\t\tsandbox.stub( mw, 'msg' ).withArgs( 'mobile-frontend-editor-continue' ).returns( 'Continue' )\n\t\t\t.withArgs( 'mobile-frontend-editor-save' ).returns( 'Save' )\n\t\t\t.withArgs( 'mobile-frontend-editor-publish' ).returns( 'Publish' );\n\n\t\tEditorGateway = require( '../../../src/mobile.editor.overlay/EditorGateway' );\n\t\tEditorOverlay = require( '../../../src/mobile.editor.overlay/EditorOverlay' );\n\t\tBlockMessage = require( '../../../src/mobile.editor.overlay/BlockMessage' );\n\n\t\t// prevent event logging requests\n\t\tsandbox.stub( EditorOverlay.prototype, 'log' ).returns( util.Deferred().resolve() );\n\t\tmessageStub = sandbox.stub( BlockMessage.prototype, 'initialize' );\n\t\tsandbox.stub( BlockMessage.prototype, 'toggle' );\n\t\tgetContentStub = sandbox.stub( EditorGateway.prototype, 'getContent' );\n\t\t// avoid waiting to load 'moment',\n\t\t// using `expiry: 'infinity'` below ensures we don't need it\n\t\tsandbox.stub( mw.loader, 'using' ).returns( { then: function ( callback ) {\n\t\t\tcallback();\n\t\t} } );\n\t\tsandbox.stub( mw, 'confirmCloseWindow' ).returns( {\n\t\t\trelease: function () {}\n\t\t} );\n\t\tsandbox.stub( window, 'scrollTo' );\n\t\tsandbox.stub( mw.util, 'getUrl' ).returns( '/w/index.php?title=User:Test' );\n\t\tsandbox.stub( mw.config, 'get' ).withArgs( 'wgMFEditorOptions' ).returns( {\n\t\t\tskipPreview: true\n\t\t} ).withArgs( 'wgFormattedNamespaces' ).returns( { 2: 'User' } );\n\t\tgetContentStub.returns( util.Deferred().resolve( {\n\t\t\ttext: 'section 0',\n\t\t\tuser: {\n\t\t\t\tid: 1,\n\t\t\t\tname: 'Foo'\n\t\t\t},\n\t\t\tblock: null,\n\t\t\tblockedByUser: null\n\t\t} ) );\n\t\tpreviewResolve = util.Deferred().resolve( { text: 'previewtest' } );\n\t\tsandbox.stub( EditorGateway.prototype, 'getPreview' )\n\t\t\t.returns( previewResolve );\n\t},\n\tafterEach: function () {\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( '#initialize, blocked user', function ( assert ) {\n\tvar dBlockedContent = util.Deferred().resolve( {\n\t\ttext: 'section 0',\n\t\tuserinfo: {\n\t\t\toptions: {\n\t\t\t\tgender: 'female'\n\t\t\t}\n\t\t},\n\t\tblockinfo: {\n\t\t\tblockedby: 'Test',\n\t\t\tblockexpiry: 'infinity',\n\t\t\tblockreason: 'Testreason'\n\t\t}\n\t} );\n\tgetContentStub.returns( dBlockedContent );\n\t// eslint-disable-next-line no-new\n\tnew EditorOverlay( {\n\t\ttitle: 'test.css'\n\t} );\n\n\treturn dBlockedContent.then( function () {\n\t\tassert.ok(\n\t\t\tmessageStub.calledWith( {\n\t\t\t\tclassName: 'drawer position-fixed',\n\t\t\t\tevents: {\n\t\t\t\t\t'click .cancel': 'onCancel',\n\t\t\t\t\tclick: 'stopPropagation'\n\t\t\t\t},\n\t\t\t\tpartial: false,\n\t\t\t\tuser: {\n\t\t\t\t\toptions: {\n\t\t\t\t\t\tgender: 'female'\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tcreator: {\n\t\t\t\t\tname: 'Test',\n\t\t\t\t\turl: testUrl\n\t\t\t\t},\n\t\t\t\texpiry: null,\n\t\t\t\tduration: null,\n\t\t\t\treason: 'Testreason'\n\t\t\t} ),\n\t\t\t'There is a drawer notice, that i am blocked from editing'\n\t\t);\n\t} );\n} );\n\nQUnit.test( '#initialize, with given page and section', function ( assert ) {\n\tvar editorOverlay = new EditorOverlay( {\n\t\ttitle: 'test',\n\t\tsectionId: 0\n\t} );\n\n\t// The gateway is initialized with the correct properties,\n\t// particularly the correct section ID.\n\tassert.strictEqual( editorOverlay.gateway.title, 'test' );\n\tassert.strictEqual( editorOverlay.gateway.isNewPage, undefined );\n\tassert.strictEqual( editorOverlay.gateway.oldId, undefined );\n\tassert.strictEqual( editorOverlay.gateway.sectionId, 0 );\n\n\treturn getContentStub().then( function () {\n\t\tassert.strictEqual( editorOverlay.$content.val(), 'section 0', 'load correct section' );\n\t} );\n} );\n\nQUnit.test( '#initialize, without a section', function ( assert ) {\n\tvar editorOverlay = new EditorOverlay( {\n\t\ttitle: 'test.css'\n\t} );\n\n\treturn getContentStub().then( function () {\n\t\tassert.strictEqual( editorOverlay.gateway.title, 'test.css' );\n\t\tassert.strictEqual( editorOverlay.gateway.isNewPage, undefined );\n\t\tassert.strictEqual( editorOverlay.gateway.oldId, undefined );\n\t\tassert.strictEqual( editorOverlay.gateway.sectionId, undefined );\n\t} );\n} );\n\nQUnit.test( '#preview', function ( assert ) {\n\tvar editorOverlay = new EditorOverlay( {\n\t\ttitle: 'test',\n\t\tsectionId: 0\n\t} );\n\n\teditorOverlay.onStageChanges();\n\n\treturn previewResolve.then( function () {\n\t\tassert.strictEqual( editorOverlay.$preview.text(), '\\npreviewtest\\n', 'preview loaded correctly' );\n\t} );\n} );\n\nQUnit.test( '#without-preview', function ( assert ) {\n\tvar editorOverlay = new EditorOverlay( {\n\t\ttitle: 'test',\n\t\tsectionId: 0\n\t} );\n\treturn getContentStub().then( function () {\n\t\tassert.strictEqual( editorOverlay.$el.find( '.continue' ).text(), 'Save', 'no preview loaded' );\n\t} );\n} );\n\nQUnit.test( '#initialize, as anonymous', function ( assert ) {\n\tvar editorOverlay = new EditorOverlay( {\n\t\ttitle: 'Main_page',\n\t\tisAnon: true\n\t} );\n\n\t// EditorOverlay triggers a call to _loadContent so will always start an async request.\n\t// Make this test async to ensure it finishes and doesn't cause side effects to other functions.\n\treturn getContentStub().then( function () {\n\t\tassert.ok( editorOverlay.$anonWarning.length > 0, 'Editorwarning (IP will be saved) visible.' );\n\t\tassert.ok( editorOverlay.$el.find( '.anonymous' ).length > 0, 'Continue login has a second class.' );\n\t} );\n} );\n","let\n\tLanguageSearcher,\n\tsandbox,\n\tjQuery = require( '../utils/jQuery' ),\n\tdom = require( '../utils/dom' ),\n\tmediaWiki = require( '../utils/mw' ),\n\too = require( '../utils/oo' ),\n\tsinon = require( 'sinon' ),\n\tapiLanguages = [\n\t\t{\n\t\t\tlang: 'ar',\n\t\t\turl: 'https://ar.wikipedia.org/wiki/%D8%A8%D8%A7%D8%B1%D8%A7%D9%83_%D8%A3%D9%88%D8%A8%D8%A7%D9%85%D8%A7',\n\t\t\ttitle: 'باراك أوباما',\n\t\t\tautonym: 'العربية'\n\t\t}, {\n\t\t\tlang: 'be',\n\t\t\turl: 'https://be.wikipedia.org/wiki/%D0%91%D0%B0%D1%80%D0%B0%D0%BA_%D0%90%D0%B1%D0%B0%D0%BC%D0%B0',\n\t\t\ttitle: 'Барак Абама',\n\t\t\tautonym: 'беларуская'\n\t\t}, {\n\t\t\tlang: 'be-x-old',\n\t\t\turl: 'https://be-x-old.wikipedia.org/wiki/%D0%91%D0%B0%D1%80%D0%B0%D0%BA_%D0%90%D0%B1%D0%B0%D0%BC%D0%B0',\n\t\t\ttitle: 'Барак Абама',\n\t\t\tautonym: 'беларуская (тарашкевіца)'\n\t\t}, {\n\t\t\tlang: 'ko',\n\t\t\turl: 'https://ko.wikipedia.org/wiki/%EB%B2%84%EB%9D%BD_%EC%98%A4%EB%B0%94%EB%A7%88',\n\t\t\ttitle: '버락 오바마',\n\t\t\tautonym: '한국어'\n\t\t}, {\n\t\t\tlang: 'ru',\n\t\t\turl: 'https://ru.wikipedia.org/wiki/%D0%9E%D0%B1%D0%B0%D0%BC%D0%B0,_%D0%91%D0%B0%D1%80%D0%B0%D0%BA',\n\t\t\ttitle: 'Обама, Барак',\n\t\t\tautonym: 'русский'\n\t\t}, {\n\t\t\tlang: 'uz',\n\t\t\turl: 'https://uz.wikipedia.org/wiki/Barak_Obama',\n\t\t\ttitle: 'Barak Obama',\n\t\t\tautonym: 'oʻzbekcha/ўзбекча'\n\t\t}, {\n\t\t\tlang: 'zh',\n\t\t\turl: 'https://zh.wikipedia.org/wiki/%E8%B4%9D%E6%8B%89%E5%85%8B%C2%B7%E5%A5%A5%E5%B7%B4%E9%A9%AC',\n\t\t\ttitle: '贝拉克·奥巴马',\n\t\t\tautonym: '中文'\n\t\t}, {\n\t\t\tlang: 'zh-min-nan',\n\t\t\turl: 'https://zh-min-nan.wikipedia.org/wiki/Barack_Obama',\n\t\t\ttitle: 'Barack Obama',\n\t\t\tlangname: 'Chinese',\n\t\t\tautonym: 'Bân-lâm-gú'\n\t\t}, {\n\t\t\tlang: 'zh-yue',\n\t\t\turl: 'https://zh-yue.wikipedia.org/wiki/%E5%A5%A7%E5%B7%B4%E9%A6%AC',\n\t\t\ttitle: '奧巴馬',\n\t\t\tautonym: '粵語'\n\t\t}, {\n\t\t\tlang: 'zu',\n\t\t\turl: 'https://zu.wikipedia.org/wiki/Barack_Obama',\n\t\t\ttitle: 'Barack Obama',\n\t\t\tautonym: 'isiZulu'\n\t\t}\n\t],\n\tdeviceLanguage = 'en-us',\n\tvariants = [\n\t\t{\n\t\t\tlang: 'foo',\n\t\t\turl: '/w/index.php?title=Barack_Obama&variant=foo',\n\t\t\tautonym: 'Foo'\n\t\t},\n\t\t{\n\t\t\tlang: 'foo-x-piglatin',\n\t\t\turl: '/w/index.php?title=Barack_Obama&variant=foo-x-piglatin',\n\t\t\tautonym: 'Igpay Atinlay'\n\t\t}\n\t],\n\tfrequentlyUsedLanguages = {\n\t\t'zh-min-nan': 1,\n\t\tzh: 2,\n\t\ten: 10,\n\t\tko: 1\n\t};\n\nfunction enterText( searcher, text ) {\n\tsearcher.$el.find( 'input[type=search]' ).val( text ).trigger( 'input' );\n}\n\nQUnit.module( 'MobileFrontend LanguageSearcher.js', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\too.setUp( sandbox, global );\n\t\tmediaWiki.setUp( sandbox, global );\n\n\t\tLanguageSearcher = require( '../../../src/mobile.languages.structured/LanguageSearcher' );\n\n\t\tsandbox.stub( mw.storage, 'get' ).withArgs( 'langMap' )\n\t\t\t.returns( JSON.stringify( frequentlyUsedLanguages ) );\n\n\t\tthis.languageSearcher = new LanguageSearcher( {\n\t\t\tlanguages: apiLanguages,\n\t\t\tvariants: variants,\n\t\t\tdeviceLanguage: deviceLanguage\n\t\t} );\n\t},\n\tafterEach: function () {\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( 'renders output', function ( assert ) {\n\tassert.strictEqual(\n\t\tthis.languageSearcher.$el.find( '.site-link-list.suggested-languages a' ).length,\n\t\t5,\n\t\t'There are 5 suggested languages including variants.'\n\t);\n\n\tassert.strictEqual(\n\t\tthis.languageSearcher.$el.find( '.site-link-list.all-languages a' ).length,\n\t\t7,\n\t\t'Seven languages are non-suggested.'\n\t);\n} );\n\nQUnit.test( 'saves the language count when link is clicked', function ( assert ) {\n\tconst stub = sandbox.stub( mw.storage, 'set' );\n\n\tthis.languageSearcher.$el.find( '[lang=foo-x-piglatin]' ).trigger( 'click' );\n\n\tassert.strictEqual( stub.callCount, 1, 'mw.storage.set is called once' );\n\tassert.deepEqual(\n\t\tstub.getCall( 0 ).args,\n\t\t[ 'langMap', '{\"zh-min-nan\":1,\"zh\":2,\"en\":10,\"ko\":1,\"foo-x-piglatin\":1}' ],\n\t\t'mw.storage.set is called with correct args'\n\t);\n} );\n\nQUnit.test( 'without variants, input event filters languages', function ( assert ) {\n\tconst languageSearcher = new LanguageSearcher( {\n\t\tlanguages: apiLanguages,\n\t\tvariants: false,\n\t\tdeviceLanguage: deviceLanguage\n\t} );\n\n\tenterText( languageSearcher, '' );\n\tassert.strictEqual(\n\t\tlanguageSearcher.$el.find( '.site-link-list a:not(.hidden)' ).length,\n\t\t10,\n\t\t'The search filter has been cleared. All 10 languages (including variants) are visible.'\n\t);\n\n\tenterText( languageSearcher, 'abcdefghij' );\n\tassert.strictEqual(\n\t\tlanguageSearcher.$el.find( '.site-link-list a:not(.hidden)' ).length,\n\t\t0,\n\t\t'No languages match \"abcdefghij\"'\n\t);\n\n\tenterText( languageSearcher, 'chin' );\n\tassert.ok(\n\t\tlanguageSearcher.$el.find( '.site-link-list a:not(.hidden)' ).length === 1 &&\n\t\tlanguageSearcher.$el.find( '.site-link-list a:not(.hidden)' ).hasClass( 'zh-min-nan' ),\n\t\t'One language (zh-min-nan) matches \"Chin\" (langname) and only that language is visible.'\n\t);\n} );\n\nQUnit.test( 'with variants, input event filters languages', function ( assert ) {\n\tenterText( this.languageSearcher, '' );\n\tassert.strictEqual(\n\t\tthis.languageSearcher.$el.find( '.site-link-list a:not(.hidden)' ).length,\n\t\t12,\n\t\t'The search filter has been cleared. All 12 languages (including variants) are visible.'\n\t);\n\n\tenterText( this.languageSearcher, 'abcdefghij' );\n\tassert.strictEqual(\n\t\tthis.languageSearcher.$el.find( '.site-link-list a:not(.hidden)' ).length,\n\t\t0,\n\t\t'No languages match \"abcdefghij\"'\n\t);\n\n\tenterText( this.languageSearcher, 'zh' );\n\tassert.strictEqual(\n\t\tthis.languageSearcher.$el.find( '.site-link-list a:not(.hidden)' ).length,\n\t\t3,\n\t\t'Three languages match \"zh\" and only those languages are visible.'\n\t);\n\n\tenterText( this.languageSearcher, 'ol' );\n\tassert.ok(\n\t\tthis.languageSearcher.$el.find( '.site-link-list a:not(.hidden)' ).length === 1 &&\n\t\tthis.languageSearcher.$el.find( '.site-link-list a:not(.hidden)' ).hasClass( 'be-x-old' ),\n\t\t'One language (be-x-old) matches \"ol\" and only that language is visible.'\n\t);\n\n\tenterText( this.languageSearcher, 'chin' );\n\tassert.ok(\n\t\tthis.languageSearcher.$el.find( '.site-link-list a:not(.hidden)' ).length === 1 &&\n\t\tthis.languageSearcher.$el.find( '.site-link-list a:not(.hidden)' ).hasClass( 'zh-min-nan' ),\n\t\t'One language (zh-min-nan) matches \"Chin\" (langname) and only that language is visible.'\n\t);\n\n\tenterText( this.languageSearcher, 'ўз' );\n\tassert.strictEqual(\n\t\tthis.languageSearcher.$el.find( '.site-link-list a:not(.hidden)' ).length,\n\t\t1,\n\t\t'One language matches \"ўз\" and only that language is visible.'\n\t);\n\n\tenterText( this.languageSearcher, 'foo' );\n\tassert.strictEqual(\n\t\tthis.languageSearcher.$el.find( '.site-link-list a:not(.hidden)' ).length,\n\t\t2,\n\t\t'Two languages match \"foo\" and only those languages are visible.'\n\t);\n\n\tenterText( this.languageSearcher, 'igpay' );\n\tassert.strictEqual(\n\t\tthis.languageSearcher.$el.find( '.site-link-list a:not(.hidden)' ).length,\n\t\t1,\n\t\t'One language matches \"igpay\" and only that language is visible.'\n\t);\n} );\n","var\n\tjQuery = require( '../utils/jQuery' ),\n\tdom = require( '../utils/dom' ),\n\tmediaWiki = require( '../utils/mw' ),\n\tsinon = require( 'sinon' ),\n\tutil,\n\tsandbox;\n\nQUnit.module( 'MobileFrontend mobile.languages.structured/util.test.js', {\n\tbeforeEach: function () {\n\t\tthis.apiLanguages = [\n\t\t\t{\n\t\t\t\tlang: 'ar',\n\t\t\t\turl: 'https://ar.wikipedia.org/wiki/%D8%A8%D8%A7%D8%B1%D8%A7%D9%83_%D8%A3%D9%88%D8%A8%D8%A7%D9%85%D8%A7',\n\t\t\t\ttitle: 'باراك أوباما',\n\t\t\t\tdir: 'rtl',\n\t\t\t\tautonym: 'العربية'\n\t\t\t}, {\n\t\t\t\tlang: 'be',\n\t\t\t\turl: 'https://be.wikipedia.org/wiki/%D0%91%D0%B0%D1%80%D0%B0%D0%BA_%D0%90%D0%B1%D0%B0%D0%BC%D0%B0',\n\t\t\t\ttitle: 'Барак Абама',\n\t\t\t\tdir: 'ltr',\n\t\t\t\tautonym: 'беларуская'\n\t\t\t}, {\n\t\t\t\tlang: 'be-x-old',\n\t\t\t\turl: 'https://be-x-old.wikipedia.org/wiki/%D0%91%D0%B0%D1%80%D0%B0%D0%BA_%D0%90%D0%B1%D0%B0%D0%BC%D0%B0',\n\t\t\t\ttitle: 'Барак Абама',\n\t\t\t\tautonym: 'беларуская (тарашкевіца)'\n\t\t\t}, {\n\t\t\t\tlang: 'es',\n\t\t\t\turl: 'https://en.wikipedia.org/wiki/Barack_Obama',\n\t\t\t\ttitle: 'Barack Obama',\n\t\t\t\tdir: 'ltr',\n\t\t\t\tautonym: 'Spanish'\n\t\t\t}, {\n\t\t\t\tlang: 'ko',\n\t\t\t\turl: 'https://ko.wikipedia.org/wiki/%EB%B2%84%EB%9D%BD_%EC%98%A4%EB%B0%94%EB%A7%88',\n\t\t\t\ttitle: '버락 오바마',\n\t\t\t\tdir: 'ltr',\n\t\t\t\tautonym: '한국어'\n\t\t\t}, {\n\t\t\t\tlang: 'ru',\n\t\t\t\turl: 'https://ru.wikipedia.org/wiki/%D0%9E%D0%B1%D0%B0%D0%BC%D0%B0,_%D0%91%D0%B0%D1%80%D0%B0%D0%BA',\n\t\t\t\ttitle: 'Обама, Барак',\n\t\t\t\tdir: 'ltr',\n\t\t\t\tautonym: 'русский'\n\t\t\t}, {\n\t\t\t\tlang: 'uz',\n\t\t\t\turl: 'https://uz.wikipedia.org/wiki/Barak_Obama',\n\t\t\t\ttitle: 'Barak Obama',\n\t\t\t\tdir: 'ltr',\n\t\t\t\tautonym: 'oʻzbekcha/ўзбекча'\n\t\t\t}, {\n\t\t\t\tlang: 'zh',\n\t\t\t\turl: 'https://zh.wikipedia.org/wiki/%E8%B4%9D%E6%8B%89%E5%85%8B%C2%B7%E5%A5%A5%E5%B7%B4%E9%A9%AC',\n\t\t\t\ttitle: '贝拉克·奥巴马',\n\t\t\t\tdir: 'ltr',\n\t\t\t\tautonym: '中文'\n\t\t\t}, {\n\t\t\t\tlang: 'zh-min-nan',\n\t\t\t\turl: 'https://zh-min-nan.wikipedia.org/wiki/Barack_Obama',\n\t\t\t\ttitle: 'Barack Obama',\n\t\t\t\tdir: 'ltr',\n\t\t\t\tautonym: 'Bân-lâm-gú'\n\t\t\t}, {\n\t\t\t\tlang: 'zh-yue',\n\t\t\t\turl: 'https://zh-yue.wikipedia.org/wiki/%E5%A5%A7%E5%B7%B4%E9%A6%AC',\n\t\t\t\ttitle: '奧巴馬',\n\t\t\t\tdir: 'ltr',\n\t\t\t\tautonym: '粵語'\n\t\t\t}, {\n\t\t\t\tlang: 'zu',\n\t\t\t\turl: 'https://zu.wikipedia.org/wiki/Barack_Obama',\n\t\t\t\ttitle: 'Barack Obama',\n\t\t\t\tdir: 'ltr',\n\t\t\t\tautonym: 'isiZulu'\n\t\t\t}\n\t\t];\n\t\tthis.apiVariants = [ {\n\t\t\tautonym: '不转换',\n\t\t\tlang: 'zh',\n\t\t\turl: '/~bmansurov/mediawiki/index.php/3?variant=zh'\n\t\t}, {\n\t\t\tautonym: '简体',\n\t\t\tlang: 'zh-hans',\n\t\t\turl: '/~bmansurov/mediawiki/index.php/3?variant=zh-hans'\n\t\t} ];\n\n\t\tthis.deviceLanguage = 'en-us';\n\n\t\tthis.frequentlyUsedLanguages = {\n\t\t\tzh: 2,\n\t\t\tko: 1\n\t\t};\n\n\t\tthis.structuredLanguages = {\n\t\t\tall: [\n\t\t\t\t{\n\t\t\t\t\tlang: 'zh-min-nan',\n\t\t\t\t\tautonym: 'Bân-lâm-gú',\n\t\t\t\t\ttitle: 'Barack Obama',\n\t\t\t\t\tdir: 'ltr',\n\t\t\t\t\turl: 'https://zh-min-nan.wikipedia.org/wiki/Barack_Obama'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlang: 'zu',\n\t\t\t\t\tautonym: 'isiZulu',\n\t\t\t\t\ttitle: 'Barack Obama',\n\t\t\t\t\tdir: 'ltr',\n\t\t\t\t\turl: 'https://zu.wikipedia.org/wiki/Barack_Obama'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlang: 'uz',\n\t\t\t\t\tautonym: 'oʻzbekcha/ўзбекча',\n\t\t\t\t\ttitle: 'Barak Obama',\n\t\t\t\t\tdir: 'ltr',\n\t\t\t\t\turl: 'https://uz.wikipedia.org/wiki/Barak_Obama'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlang: 'es',\n\t\t\t\t\tautonym: 'Spanish',\n\t\t\t\t\ttitle: 'Barack Obama',\n\t\t\t\t\tdir: 'ltr',\n\t\t\t\t\turl: 'https://en.wikipedia.org/wiki/Barack_Obama'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlang: 'be',\n\t\t\t\t\tautonym: 'беларуская',\n\t\t\t\t\ttitle: 'Барак Абама',\n\t\t\t\t\tdir: 'ltr',\n\t\t\t\t\turl: 'https://be.wikipedia.org/wiki/%D0%91%D0%B0%D1%80%D0%B0%D0%BA_%D0%90%D0%B1%D0%B0%D0%BC%D0%B0'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlang: 'be-x-old',\n\t\t\t\t\tautonym: 'беларуская (тарашкевіца)',\n\t\t\t\t\ttitle: 'Барак Абама',\n\t\t\t\t\tdir: 'ltr',\n\t\t\t\t\turl: 'https://be-x-old.wikipedia.org/wiki/%D0%91%D0%B0%D1%80%D0%B0%D0%BA_%D0%90%D0%B1%D0%B0%D0%BC%D0%B0'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlang: 'ru',\n\t\t\t\t\tautonym: 'русский',\n\t\t\t\t\ttitle: 'Обама, Барак',\n\t\t\t\t\tdir: 'ltr',\n\t\t\t\t\turl: 'https://ru.wikipedia.org/wiki/%D0%9E%D0%B1%D0%B0%D0%BC%D0%B0,_%D0%91%D0%B0%D1%80%D0%B0%D0%BA'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlang: 'ar',\n\t\t\t\t\tautonym: 'العربية',\n\t\t\t\t\ttitle: 'باراك أوباما',\n\t\t\t\t\tdir: 'rtl',\n\t\t\t\t\turl: 'https://ar.wikipedia.org/wiki/%D8%A8%D8%A7%D8%B1%D8%A7%D9%83_%D8%A3%D9%88%D8%A8%D8%A7%D9%85%D8%A7'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlang: 'zh-yue',\n\t\t\t\t\tautonym: '粵語',\n\t\t\t\t\ttitle: '奧巴馬',\n\t\t\t\t\tdir: 'ltr',\n\t\t\t\t\turl: 'https://zh-yue.wikipedia.org/wiki/%E5%A5%A7%E5%B7%B4%E9%A6%AC'\n\t\t\t\t}\n\t\t\t],\n\t\t\tsuggested: [\n\t\t\t\t{\n\t\t\t\t\tfrequency: 2,\n\t\t\t\t\tlang: 'zh',\n\t\t\t\t\tautonym: '中文',\n\t\t\t\t\ttitle: '贝拉克·奥巴马',\n\t\t\t\t\tdir: 'ltr',\n\t\t\t\t\turl: 'https://zh.wikipedia.org/wiki/%E8%B4%9D%E6%8B%89%E5%85%8B%C2%B7%E5%A5%A5%E5%B7%B4%E9%A9%AC'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tfrequency: 1,\n\t\t\t\t\tlang: 'ko',\n\t\t\t\t\tautonym: '한국어',\n\t\t\t\t\ttitle: '버락 오바마',\n\t\t\t\t\tdir: 'ltr',\n\t\t\t\t\turl: 'https://ko.wikipedia.org/wiki/%EB%B2%84%EB%9D%BD_%EC%98%A4%EB%B0%94%EB%A7%88'\n\t\t\t\t}\n\t\t\t]\n\t\t};\n\n\t\tsandbox = sinon.sandbox.create();\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\tmediaWiki.setUp( sandbox, global );\n\t\tsandbox.stub( mw.storage, 'get' ).withArgs( 'langMap' )\n\t\t\t.returns( JSON.stringify( this.frequentlyUsedLanguages ) );\n\n\t\tutil = require( '../../../src/mobile.languages.structured/util' );\n\n\t\tthis.saveSpy = sandbox.stub( util, 'saveFrequentlyUsedLanguages' );\n\t},\n\tafterEach: function () {\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( '#getFrequentlyUsedLanguages', function ( assert ) {\n\n\tassert.propEqual( util.getFrequentlyUsedLanguages(), this.frequentlyUsedLanguages,\n\t\t'Frequently used languages is correct.' );\n} );\n\nQUnit.test( '#saveLanguageUsageCount', function ( assert ) {\n\tutil.saveLanguageUsageCount( 'ko', util.getFrequentlyUsedLanguages() );\n\tassert.ok( this.saveSpy.calledWith( {\n\t\tzh: 2,\n\t\tko: 2\n\t} ), 'Frequently used language is correctly saved.' );\n} );\n\nQUnit.test( '#getStructuredLanguages', function ( assert ) {\n\tvar result = util.getStructuredLanguages(\n\t\tthis.apiLanguages, false, this.frequentlyUsedLanguages, this.deviceLanguage\n\t);\n\n\tassert.propEqual(\n\t\tresult,\n\t\tthis.structuredLanguages,\n\t\t'Structured languages are correct, including sort order.'\n\t);\n} );\n\nQUnit.test( '#getStructuredLanguages device language', function ( assert ) {\n\tvar result =\n\t\tutil.getStructuredLanguages( this.apiLanguages, false, {}, 'es-lx' ).suggested[0].lang;\n\n\t// device language is a variant and only the parent language is available\n\tassert.strictEqual(\n\t\tresult,\n\t\t'es',\n\t\t'\"es\" is correctly selected as a suggested language even though the device language is \"es-lx\".'\n\t);\n} );\n\nQUnit.test( '#getStructuredLanguages variants', function ( assert ) {\n\tvar suggestedLanguages,\n\t\tvariantsMap = {};\n\n\tsuggestedLanguages = util.getStructuredLanguages(\n\t\tthis.apiLanguages, this.apiVariants, {}, this.deviceLanguage\n\t).suggested;\n\tthis.apiVariants.forEach( function ( variant ) {\n\t\tvariantsMap[ variant.lang ] = variant;\n\t} );\n\tsuggestedLanguages.forEach( function ( suggestedLanguage ) {\n\t\tassert.ok(\n\t\t\tObject.prototype.hasOwnProperty.call( variantsMap, suggestedLanguage.lang ),\n\t\t\t'Variant \"' + suggestedLanguage.lang + '\" is in the list of suggested languages.'\n\t\t);\n\t} );\n} );\n","var sandbox, ImageOverlay,\n\tutil = require( '../../../src/mobile.startup/util' ),\n\tjQuery = require( '../utils/jQuery' ),\n\tdom = require( '../utils/dom' ),\n\tmediaWiki = require( '../utils/mw' ),\n\too = require( '../utils/oo' ),\n\tsinon = require( 'sinon' );\n\nQUnit.module( 'MobileFrontend mobile.mediaViewer/ImageCarousel.js', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\too.setUp( sandbox, global );\n\t\tmediaWiki.setUp( sandbox, global );\n\t\tImageOverlay = require( '../../../src/mobile.mediaViewer/ImageCarousel' );\n\n\t\tthis.image = {\n\t\t\tdescriptionurl: 'https://commons.wikimedia.org/wiki/File:The_Montgomery,_San_Francisco.jpg',\n\t\t\tthumbheight: 1024,\n\t\t\tthumburl: 'https://upload.wikimedia.org/wikipedia/commons/thumb/b/b1/The_Montgomery%2C_San_Francisco.jpg/676px-The_Montgomery%2C_San_Francisco.jpg',\n\t\t\tthumbwidth: 676,\n\t\t\turl: 'https://upload.wikimedia.org/wikipedia/commons/b/b1/The_Montgomery%2C_San_Francisco.jpg'\n\t\t};\n\t\tthis.imageGateway = {\n\t\t\tgetThumb: function () {\n\t\t\t\treturn util.Deferred().resolve( {\n\t\t\t\t\tquery: {\n\t\t\t\t\t\tpages: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\timageinfo: [ this.image ]\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t]\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\t\t};\n\t\tthis.router = {\n\t\t\tgetPath: function () {\n\t\t\t\treturn '/media/File%3AA_cursiva.gif';\n\t\t\t}\n\t\t};\n\t\tthis.thumbnails = [\n\t\t\t{\n\t\t\t\tfilename: 'foo',\n\t\t\t\tgetFileName: function () { return ''; },\n\t\t\t\tgetPath: function () { return ''; },\n\t\t\t\tgetDescription: function () { return ''; }\n\t\t\t},\n\t\t\t{\n\t\t\t\tfilename: 'bar',\n\t\t\t\tgetFileName: function () { return ''; },\n\t\t\t\tgetPath: function () { return ''; },\n\t\t\t\tgetDescription: function () { return ''; }\n\t\t\t}\n\t\t];\n\t},\n\tafterEach: function () {\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( 'Shows details bar and image with successful api response', function ( assert ) {\n\tvar overlay = new ImageOverlay( {\n\t\tgateway: this.imageGateway,\n\t\ttitle: decodeURIComponent( this.image.url ),\n\t\tcaption: 'The Montgomery in 2012.',\n\t\trouter: this.router,\n\t\teventBus: {\n\t\t\ton: function () {}\n\t\t}\n\t} );\n\n\treturn this.imageGateway.getThumb().then( function () {\n\t\tassert.strictEqual( overlay.$el.find( 'img' ).length, 1, 'Image is present.' );\n\t\tassert.strictEqual( overlay.$el.find( '.load-fail-msg' ).length, 0, 'Load error msg is not visible' );\n\t\tassert.strictEqual( overlay.$el.find( '.image-details.is-visible' ).length, 1, 'Details bar present' );\n\t} );\n} );\n\nQUnit.test( 'Shows error message with failed api response', function ( assert ) {\n\tvar overlay, imageGateway = {\n\t\tgetThumb: function () {\n\t\t\treturn util.Deferred().reject( 'Load Error' );\n\t\t}\n\t};\n\n\toverlay = new ImageOverlay( {\n\t\tgateway: imageGateway,\n\t\ttitle: decodeURIComponent( this.image.url ),\n\t\tcaption: 'The Montgomery in 2012.',\n\t\trouter: this.router,\n\t\teventBus: {\n\t\t\ton: function () {}\n\t\t}\n\t} );\n\n\treturn imageGateway.getThumb().catch( function () {\n\t\tassert.strictEqual( overlay.$el.find( '.load-fail-msg' ).length, 1, 'Load error msg is visible' );\n\t\tassert.strictEqual( overlay.$el.find( '.image-details.is-visible' ).length, 0, 'Details bar is hidden' );\n\t} );\n} );\n\nQUnit.test( 'Toggling of details is disabled when overlay has load failure', function ( assert ) {\n\tvar overlay, imageGateway = {\n\t\tgetThumb: function () {\n\t\t\treturn util.Deferred().reject( 'Load Error' );\n\t\t}\n\t};\n\n\toverlay = new ImageOverlay( {\n\t\tgateway: imageGateway,\n\t\ttitle: decodeURIComponent( this.image.url ),\n\t\tcaption: 'The Montgomery in 2012.',\n\t\tthumbnails: this.thumbnails,\n\t\trouter: this.router,\n\t\teventBus: {\n\t\t\ton: function () {}\n\t\t}\n\t} );\n\n\treturn imageGateway.getThumb().catch( function () {\n\t\tassert.strictEqual( overlay.$el.find( '.image-details.is-visible' ).length, 0, 'Details bar is hidden' );\n\t\tassert.notStrictEqual( overlay.$el.find( '.image-details' ), 'none', 'Slider buttons are shown' );\n\t\tassert.notStrictEqual( overlay.$el.find( '.prev' ), 'none', 'Slider buttons are still shown' );\n\n\t\toverlay.$el.find( '.image-wrapper' ).trigger( 'click' );\n\n\t\t// Assert that toggle didn't occur (would add display: none)\n\t\tassert.notStrictEqual( overlay.$el.find( '.image-details' ), 'none', 'Slider buttons are shown' );\n\t\tassert.notStrictEqual( overlay.$el.find( '.prev' ), 'none', 'Slider buttons are still shown' );\n\t} );\n} );\n\nQUnit.test( 'Toggling of details is enabled when overlay loads successfully', function ( assert ) {\n\tvar overlay = new ImageOverlay( {\n\t\tgateway: this.imageGateway,\n\t\ttitle: decodeURIComponent( this.image.url ),\n\t\tcaption: 'The Montgomery in 2012.',\n\t\tthumbnails: this.thumbnails,\n\t\trouter: this.router,\n\t\teventBus: {\n\t\t\ton: function () {}\n\t\t}\n\t} );\n\n\treturn this.imageGateway.getThumb().then( function () {\n\t\tassert.strictEqual( overlay.$el.find( '.image-details.is-visible' ).length, 1, 'Details bar is shown' );\n\t\tassert.notStrictEqual( overlay.$el.find( '.image-details' ).css( 'display' ), 'none', 'Ensure display none rule is not set' );\n\t\tassert.notStrictEqual( overlay.$el.find( '.prev' ).css( 'display' ), 'none', 'Slider buttons are shown' );\n\n\t\toverlay.$el.find( '.image-wrapper' ).trigger( 'click' );\n\n\t\tassert.strictEqual( overlay.$el.find( '.image-details' ).css( 'display' ), 'none', 'Details bar is hidden' );\n\t\tassert.strictEqual( overlay.$el.find( '.slider-button' ).css( 'display' ), 'none', 'Slider buttons are hidden' );\n\t} );\n} );\n","var sandbox, ImageGateway, findSizeBucket,\n\tsinon = require( 'sinon' ),\n\tdom = require( '../utils/dom' ),\n\tmediaWiki = require( '../utils/mw' ),\n\tjQuery = require( '../utils/jQuery' ),\n\tutil = require( '../../../src/mobile.startup/util' );\n\nQUnit.module( 'MobileFrontend mobile.mediaViewer/ImageGateway', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\tmediaWiki.setUp( sandbox, global );\n\t\tImageGateway = require( '../../../src/mobile.mediaViewer/ImageGateway' );\n\t\tfindSizeBucket = ImageGateway._findSizeBucket;\n\t},\n\tafterEach: function () {\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( '#findSizeBucket', function ( assert ) {\n\tassert.strictEqual( findSizeBucket( 300 ), 320, 'value lower than bucket' );\n\tassert.strictEqual( findSizeBucket( 800 ), 800, 'exact value' );\n\tassert.strictEqual( findSizeBucket( 9999 ), 2880, 'value greater than last bucket' );\n} );\n\nQUnit.test( 'ImageGateway#getThumb (missing page)', function ( assert ) {\n\tvar gateway,\n\t\tapi = {\n\t\t\tget: function () {\n\t\t\t\treturn util.Deferred().resolve( {\n\t\t\t\t\tquery: {\n\t\t\t\t\t\tpages: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttitle: 'Hello',\n\t\t\t\t\t\t\t\tmissing: true\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t]\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\t\t};\n\tgateway = new ImageGateway( { api: api } );\n\tassert.rejects(\n\t\tgateway.getThumb( 'Missing' ),\n\t\tfunction ( err ) {\n\t\t\treturn err.message.indexOf( 'The API failed' ) !== -1;\n\t\t},\n\t\t'A missing page throws an error which the client must handle'\n\t);\n} );\n","var\n\tjQuery = require( '../utils/jQuery' ),\n\tdom = require( '../utils/dom' ),\n\tmediaWiki = require( '../utils/mw' ),\n\too = require( '../utils/oo' ),\n\tsinon = require( 'sinon' ),\n\tapi = {\n\t\tget: function () {}\n\t},\n\tsandbox,\n\tNearbyGateway,\n\tNearby,\n\tutil;\n\nQUnit.module( 'MobileFrontend Nearby.js', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\too.setUp( sandbox, global );\n\t\tmediaWiki.setUp( sandbox, global );\n\n\t\tutil = require( '../../../src/mobile.startup/util' );\n\t\tNearbyGateway = require( '../../../src/mobile.special.nearby.scripts/NearbyGateway' );\n\t\tNearby = require( '../../../src/mobile.special.nearby.scripts/Nearby' );\n\t},\n\tafterEach: function () {\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( 'refresh() with no results, renders empty list', function ( assert ) {\n\tvar $el = util.parseHTML( '<div>' ), nearby,\n\t\tspy = sandbox.stub( NearbyGateway.prototype, 'getPages' )\n\t\t\t.returns( util.Deferred().resolve( [] ) ),\n\t\topts = {\n\t\t\tapi: api,\n\t\t\tlatitude: 37.7,\n\t\t\tlongitude: -122,\n\t\t\trange: 1000,\n\t\t\tel: $el,\n\t\t\teventBus: {\n\t\t\t\temit: function () {}\n\t\t\t}\n\t\t};\n\tnearby = new Nearby( opts );\n\n\treturn nearby.refresh( opts ).then( function () {\n\t\tassert.ok( spy.calledWithMatch( {\n\t\t\tlatitude: 37.7,\n\t\t\tlongitude: -122\n\t\t}, 1000 ), 'Check API got called' );\n\t\tassert.strictEqual( $el.find( 'li' ).length, 0, '0 pages render.' );\n\t\tassert.strictEqual( $el.find( '.errorbox' ).length, 1, 'Error message shown.' );\n\t\tassert.strictEqual( $el.find( '.loading' ).is( ':visible' ), false, 'No loader shown.' );\n\t} );\n} );\n\nQUnit.test( 'refresh() with results, renders with a location', function ( assert ) {\n\tvar\n\t\tspy,\n\t\tresp = {\n\t\t\tquery: {\n\t\t\t\tpages: [\n\t\t\t\t\t{\n\t\t\t\t\t\tpageid: 2,\n\t\t\t\t\t\twatched: true\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tpageid: 3,\n\t\t\t\t\t\twatched: false\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tpageid: 4,\n\t\t\t\t\t\twatched: false\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t$el = util.parseHTML( '<div>' ), nearby,\n\t\topts = {\n\t\t\tapi: api,\n\t\t\tlatitude: 37.7,\n\t\t\tlongitude: -122,\n\t\t\trange: 1000,\n\t\t\tel: $el,\n\t\t\teventBus: {\n\t\t\t\temit: function () {}\n\t\t\t}\n\t\t};\n\n\t// prevent hits to api due to watch status lookup\n\tsandbox.stub( api, 'get' ).returns( util.Deferred().resolve( resp ) );\n\n\tspy = sandbox.stub( NearbyGateway.prototype, 'getPages' )\n\t\t.returns( util.Deferred().resolve( [\n\t\t\t{\n\t\t\t\ttitle: 'Sutro Tower',\n\t\t\t\tid: 2\n\t\t\t},\n\t\t\t{\n\t\t\t\ttitle: 'Golden Gate bridge',\n\t\t\t\tid: 3\n\t\t\t},\n\t\t\t{\n\t\t\t\ttitle: 'Golden Gate Park',\n\t\t\t\tid: 4\n\t\t\t}\n\t\t] ) );\n\n\tnearby = new Nearby( opts );\n\treturn nearby.refresh( opts ).then( function () {\n\t\tassert.ok( spy.calledWithMatch( {\n\t\t\tlatitude: 37.7,\n\t\t\tlongitude: -122\n\t\t}, 1000 ), 'Check API got called' );\n\t\tassert.strictEqual( $el.find( 'li' ).length, 3, '3 pages render.' );\n\t} );\n} );\n\nQUnit.test( 'refresh() with server error, renders error', function ( assert ) {\n\tvar\n\t\t$el = util.parseHTML( '<div>' ),\n\t\tspy = sandbox.stub( NearbyGateway.prototype, 'getPages' )\n\t\t\t.returns( util.Deferred().reject() ),\n\t\tnearby,\n\t\topts = {\n\t\t\tapi: api,\n\t\t\tlatitude: 37.7,\n\t\t\tlongitude: -122,\n\t\t\trange: 1000,\n\t\t\tel: $el,\n\t\t\teventBus: {\n\t\t\t\temit: function () {}\n\t\t\t}\n\t\t};\n\tnearby = new Nearby( opts );\n\n\treturn nearby.refresh( opts ).then( function () {\n\t\tassert.ok( spy.calledWithMatch( {\n\t\t\tlatitude: 37.7,\n\t\t\tlongitude: -122\n\t\t}, 1000 ), 'Check API got called' );\n\t\tassert.strictEqual( $el.find( '.errorbox' ).length, 1, 'Check error got rendered' );\n\t\tassert.strictEqual( $el.find( '.errorbox h2' ).text(),\n\t\t\tnearby.errorMessages.http.heading, 'Check it is the correct heading' );\n\t} );\n} );\n\nQUnit.test( 'refresh() getting a title triggers different API method', function ( assert ) {\n\tvar\n\t\tspy,\n\t\t$el = util.parseHTML( '<div>' ),\n\t\tpageTitle = 'Hello Friends!',\n\t\tnearby,\n\t\topts = {\n\t\t\tapi: api,\n\t\t\tpageTitle: pageTitle,\n\t\t\trange: 1000,\n\t\t\tel: $el,\n\t\t\teventBus: {\n\t\t\t\temit: function () {}\n\t\t\t}\n\t\t};\n\n\tspy = sandbox.stub( NearbyGateway.prototype, 'getPagesAroundPage' )\n\t\t.returns( util.Deferred().reject() );\n\tnearby = new Nearby( opts );\n\tnearby.refresh( opts );\n\n\tassert.ok( spy.calledWithMatch( pageTitle, 1000 ), 'Check API got called' );\n} );\n","var\n\tsandbox,\n\tNearbyGateway,\n\tutil,\n\tjQuery = require( '../utils/jQuery' ),\n\tdom = require( '../utils/dom' ),\n\tmediaWiki = require( '../utils/mw' ),\n\too = require( '../utils/oo' ),\n\tsinon = require( 'sinon' );\n\nQUnit.module( 'MobileFrontend NearbyGateway.js', {\n\tbeforeEach: function () {\n\t\tvar api;\n\n\t\tsandbox = sinon.sandbox.create();\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\too.setUp( sandbox, global );\n\t\tmediaWiki.setUp( sandbox, global );\n\n\t\t// needed for extendSearchParams to not throw exception about feature not\n\t\t// supporting wikibase descriptions in headless tests\n\t\tsandbox.stub( mw.config, 'get' )\n\t\t\t.withArgs( 'wgArticlePath' ).returns( '/w/' )\n\t\t\t.withArgs( 'wgMFDisplayWikibaseDescriptions', {} )\n\t\t\t.returns( {\n\t\t\t\tnearby: true\n\t\t\t} )\n\t\t\t// needed bc Page.js expects this call to return an array\n\t\t\t.withArgs( 'wgMFMobileFormatterHeadings', [ 'h1', 'h2', 'h3', 'h4', 'h5' ] )\n\t\t\t.returns( [ 'h1', 'h2', 'h3', 'h4', 'h5' ] );\n\n\t\tutil = require( '../../../src/mobile.startup/util' );\n\t\tNearbyGateway = require( '../../../src/mobile.special.nearby.scripts/NearbyGateway' );\n\n\t\tapi = {\n\t\t\tajax: function () {}\n\t\t};\n\n\t\tsandbox.stub( mw, 'msg' ).returns( '$1' );\n\n\t\tthis.nearbyGateway = new NearbyGateway( { api: api } );\n\n\t\t// stub mw.language behavior so we don't have to bring in the real thing\n\t\tsandbox.stub( mw.language, 'convertNumber', function ( arg ) {\n\t\t\treturn arg === '1.20' ? '1.2' : String( arg );\n\t\t} );\n\n\t\tsandbox.stub( api, 'ajax', function () {\n\t\t\treturn util.Deferred().resolve( {\n\t\t\t\tquery: {\n\t\t\t\t\tpages: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tpageid: 20004112,\n\t\t\t\t\t\t\tns: 0,\n\t\t\t\t\t\t\ttitle: 'The Montgomery (San Francisco)',\n\t\t\t\t\t\t\tthumbnail: {\n\t\t\t\t\t\t\t\tsource: 'https://upload.wikimedia.org/wikipedia/commons/thumb/b/b1/The_Montgomery%2C_San_Francisco.jpg/119px-The_Montgomery%2C_San_Francisco.jpg',\n\t\t\t\t\t\t\t\twidth: 119,\n\t\t\t\t\t\t\t\theight: 180\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tpageimage: 'The_Montgomery,_San_Francisco.jpg',\n\t\t\t\t\t\t\tcoordinates: [ {\n\t\t\t\t\t\t\t\tlat: 37.787,\n\t\t\t\t\t\t\t\tlon: -122.41,\n\t\t\t\t\t\t\t\tprimary: '',\n\t\t\t\t\t\t\t\tglobe: 'earth',\n\t\t\t\t\t\t\t\tdist: 120200\n\t\t\t\t\t\t\t} ]\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tpageid: 18618509,\n\t\t\t\t\t\t\tns: 0,\n\t\t\t\t\t\t\ttitle: 'Wikimedia Foundation',\n\t\t\t\t\t\t\tthumbnail: {\n\t\t\t\t\t\t\t\tsource: 'https://upload.wikimedia.org/wikipedia/commons/thumb/c/c4/Wikimedia_Foundation_RGB_logo_with_text.svg/180px-Wikimedia_Foundation_RGB_logo_with_text.svg.png',\n\t\t\t\t\t\t\t\twidth: 180,\n\t\t\t\t\t\t\t\theight: 180\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tpageimage: 'Wikimedia_Foundation_RGB_logo_with_text.svg',\n\t\t\t\t\t\t\tcoordinates: [ {\n\t\t\t\t\t\t\t\tlat: 37.787,\n\t\t\t\t\t\t\t\tlon: -122.51,\n\t\t\t\t\t\t\t\tprimary: '',\n\t\t\t\t\t\t\t\tglobe: 'earth',\n\t\t\t\t\t\t\t\tdist: 0\n\t\t\t\t\t\t\t} ]\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tpageid: 9297443,\n\t\t\t\t\t\t\tns: 0,\n\t\t\t\t\t\t\ttitle: 'W San Francisco',\n\t\t\t\t\t\t\tcoordinates: [ {\n\t\t\t\t\t\t\t\tlat: 37.7854,\n\t\t\t\t\t\t\t\tlon: -122.61,\n\t\t\t\t\t\t\t\tprimary: '',\n\t\t\t\t\t\t\t\tglobe: 'earth',\n\t\t\t\t\t\t\t\tdist: 177400\n\t\t\t\t\t\t\t} ]\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t} );\n\t\t} );\n\t},\n\tafterEach: function () {\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( '_distanceMessage()', function ( assert ) {\n\tvar\n\t\tself = this,\n\t\tmsgKm = 'mobile-frontend-nearby-distance',\n\t\tmsgM = 'mobile-frontend-nearby-distance-meters',\n\t\ttests = [\n\t\t\t[ 0.4834, msgM, '490' ],\n\t\t\t[ 0.5, msgM, '500' ],\n\t\t\t[ 0.723, msgM, '730' ],\n\t\t\t[ 0.999, msgKm, '1' ],\n\t\t\t[ 1.2, msgKm, '1.2' ],\n\t\t\t[ 1.588, msgKm, '1.59' ],\n\t\t\t[ 1.123, msgKm, '1.13' ],\n\t\t\t[ 2.561, msgKm, '2.6' ],\n\t\t\t[ 10.8334, msgKm, '10.9' ]\n\t\t];\n\n\ttests.forEach( function ( test, i ) {\n\t\tself.nearbyGateway._distanceMessage( test[ 0 ] );\n\n\t\tassert.propEqual(\n\t\t\tmw.msg.getCall( i ).args,\n\t\t\t[\n\t\t\t\ttest[ 1 ], test[ 2 ]\n\t\t\t]\n\t\t);\n\t} );\n} );\n\nQUnit.test( 'getPages()', function ( assert ) {\n\treturn this.nearbyGateway.getPages( {\n\t\tlatitude: 37.787,\n\t\tlongitude: -122.51\n\t} ).then( function ( pages ) {\n\t\tassert.strictEqual( pages.length, 3 );\n\t\tassert.strictEqual( pages[ 0 ].title, 'Wikimedia Foundation' );\n\t\tassert.strictEqual( pages[ 0 ].thumbnail.isLandscape, false );\n\t\tassert.strictEqual( pages[ 2 ].title, 'W San Francisco' );\n\t\tassert.strictEqual( pages[ 2 ].thumbnail, false );\n\t\tassert.strictEqual( pages[ 2 ].dist.toPrecision( 6 ), '177.400' );\n\t} );\n} );\n\nQUnit.test( 'getPagesAroundPage()', function ( assert ) {\n\treturn this.nearbyGateway.getPagesAroundPage( 'Wikimedia Foundation' ).then( function ( pages ) {\n\t\tassert.strictEqual( pages.length, 2 );\n\t\tassert.strictEqual( pages[ 1 ].title, 'W San Francisco' );\n\t\tassert.strictEqual( pages[ 1 ].thumbnail, false );\n\t\tassert.strictEqual( pages[ 1 ].dist.toPrecision( 6 ), '177.400' );\n\t} );\n} );\n","var PhotoListGateway, sandbox, getDescription,\n\tsinon = require( 'sinon' ),\n\tdom = require( '../utils/dom' ),\n\tjQuery = require( '../utils/jQuery' );\n\nQUnit.module( 'PhotoListGateway', {\n\tbeforeEach: function () {\n\t\t// All this stubbing really shouldn't be needed to test getDescription\n\t\t// But it is since require( '../mobile.startup/util' ) is imported by PhotoListGateway\n\t\t// Consider putting getDescription in a separate file to separate it from the View.\n\t\tsandbox = sinon.sandbox.create();\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\tPhotoListGateway = require( '../../../src/mobile.special.uploads.scripts/PhotoListGateway' );\n\t\tgetDescription = PhotoListGateway.test.getDescription;\n\t},\n\tafterEach: function () {\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( '#getDescription', function ( assert ) {\n\tvar tests = [\n\t\t[ 'File:Pirates in SF 2013-04-03 15-44.png', 'Pirates in SF' ],\n\t\t[ 'File:Unpadded 9 pirates in SF 2013-04-03 15-9.png', 'Unpadded 9 pirates in SF' ],\n\t\t[ 'File:Jon lies next to volcano 2013-03-18 13-37.jpeg', 'Jon lies next to volcano' ],\n\t\t[ 'hello world 37.jpg', 'hello world 37' ],\n\t\t[ 'hello world again.jpeg', 'hello world again' ],\n\t\t[ 'Fichier:French Photo Timestamp 2013-04-03 15-44.jpg', 'French Photo Timestamp' ],\n\t\t[ 'Fichier:Full stop. Photo.unknownfileextension', 'Full stop. Photo' ],\n\t\t[ 'File:No file extension but has a . in the title', 'No file extension but has a . in the title' ],\n\t\t[ 'Fichier:French Photo.jpg', 'French Photo' ]\n\t];\n\n\ttests.forEach( function ( test, i ) {\n\t\tvar val = getDescription( test[ 0 ] );\n\t\tassert.strictEqual( val, test[ 1 ], 'test ' + i );\n\t} );\n} );\n","var\n\tjQuery = require( '../utils/jQuery' ),\n\tdom = require( '../utils/dom' ),\n\tmediaWiki = require( '../utils/mw' ),\n\too = require( '../utils/oo' ),\n\tsinon = require( 'sinon' ),\n\tWatchList,\n\tIcon,\n\tsandbox;\n\nQUnit.module( 'MobileFrontend WatchList.js', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\too.setUp( sandbox, global );\n\t\tmediaWiki.setUp( sandbox, global );\n\n\t\tsandbox.stub( mw.user, 'isAnon' ).returns( false );\n\n\t\tWatchList = require( '../../../src/mobile.special.watchlist.scripts/WatchList' );\n\t\tIcon = require( '../../../src/mobile.startup/Icon' );\n\t},\n\tafterEach: function () {\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( 'In watched mode', function ( assert ) {\n\tvar\n\t\tstub = {\n\t\t\tget: sandbox.stub()\n\t\t},\n\t\tpl = new WatchList( {\n\t\t\teventBus: {\n\t\t\t\ton: function () {},\n\t\t\t\toff: function () {}\n\t\t\t},\n\t\t\tapi: stub,\n\t\t\tpages: [\n\t\t\t\t{ title: 'Title 30' },\n\t\t\t\t{ title: 'Title 50' },\n\t\t\t\t{\n\t\t\t\t\ttitle: 'Title 60',\n\t\t\t\t\twatched: true\n\t\t\t\t}\n\t\t\t]\n\t\t} ),\n\t\twatchIconName = new Icon( {\n\t\t\tname: 'watched'\n\t\t} ).getGlyphClassName();\n\n\t// Avoid API requests due to scroll events (https://phabricator.wikimedia.org/T116258)\n\tpl.scrollEndEventEmitter.disable();\n\n\tassert.ok( stub.get.notCalled, 'Callback avoided' );\n\tassert.strictEqual( pl.$el.find( '.watch-this-article' ).length, 3, '3 articles have watch stars...' );\n\tassert.strictEqual( pl.$el.find( '.' + watchIconName ).length, 3, '...and all are marked as watched.' );\n} );\n","var\n\tWatchListGateway,\n\tsandbox,\n\tjQuery = require( '../utils/jQuery' ),\n\tdom = require( '../utils/dom' ),\n\tmediaWiki = require( '../utils/mw' ),\n\too = require( '../utils/oo' ),\n\tsinon = require( 'sinon' ),\n\tutil = require( '../../../src/mobile.startup/util' ),\n\tresponse = {\n\t\tcontinue: {\n\t\t\tpageimages: {\n\t\t\t\tpicontinue: 9\n\t\t\t}\n\t\t},\n\t\twarnings: {\n\t\t\tquery: {\n\t\t\t\t'*': 'Formatting of continuation data will be changing soon. To continue using the current formatting, use the \\'rawcontinue\\' parameter. To begin using the new format, pass an empty string for \\'continue\\' in the initial query.'\n\t\t\t}\n\t\t},\n\t\tquery: {\n\t\t\tpages: [\n\t\t\t\t{\n\t\t\t\t\tpageid: 2,\n\t\t\t\t\tns: 0,\n\t\t\t\t\ttitle: 'Burrito',\n\t\t\t\t\tcontentmodel: 'wikitext',\n\t\t\t\t\tpagelanguage: 'en',\n\t\t\t\t\ttouched: '2014-12-17T10:06:49Z',\n\t\t\t\t\tlastrevid: 552,\n\t\t\t\t\tlength: 33534\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tpageid: 3,\n\t\t\t\t\tns: 0,\n\t\t\t\t\ttitle: 'Albert Einstein',\n\t\t\t\t\tcontentmodel: 'wikitext',\n\t\t\t\t\tpagelanguage: 'en',\n\t\t\t\t\ttouched: '2014-12-16T17:33:22Z',\n\t\t\t\t\tlastrevid: 4,\n\t\t\t\t\tlength: 19\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tpageid: 9,\n\t\t\t\t\tns: 0,\n\t\t\t\t\ttitle: 'Anne Dallas Dudley',\n\t\t\t\t\tcontentmodel: 'wikitext',\n\t\t\t\t\tpagelanguage: 'en',\n\t\t\t\t\ttouched: '2014-12-17T10:00:13Z',\n\t\t\t\t\tlastrevid: 18,\n\t\t\t\t\tlength: 12663\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tpageid: 10,\n\t\t\t\t\tns: 0,\n\t\t\t\t\ttitle: 'San Francisco',\n\t\t\t\t\tcontentmodel: 'wikitext',\n\t\t\t\t\tpagelanguage: 'en',\n\t\t\t\t\ttouched: '2014-12-17T10:04:55Z',\n\t\t\t\t\tlastrevid: 546,\n\t\t\t\t\tlength: 373791\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tpageid: 708,\n\t\t\t\t\tns: 0,\n\t\t\t\t\ttitle: 'Functional logic programming',\n\t\t\t\t\tcontentmodel: 'wikitext',\n\t\t\t\t\tpagelanguage: 'en',\n\t\t\t\t\ttouched: '2015-01-12T13:04:23Z',\n\t\t\t\t\tlastrevid: 1307,\n\t\t\t\t\tlength: 1392,\n\t\t\t\t\tnew: ''\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tpageid: 720,\n\t\t\t\t\tns: 0,\n\t\t\t\t\ttitle: 'Functional programming',\n\t\t\t\t\tcontentmodel: 'wikitext',\n\t\t\t\t\tpagelanguage: 'en',\n\t\t\t\t\ttouched: '2015-01-12T13:04:35Z',\n\t\t\t\t\tlastrevid: 1319,\n\t\t\t\t\tlength: 54839,\n\t\t\t\t\tnew: ''\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tns: 0,\n\t\t\t\t\ttitle: 'zzzz',\n\t\t\t\t\tmissing: true,\n\t\t\t\t\tcontentmodel: 'wikitext',\n\t\t\t\t\tpagelanguage: 'en'\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t};\n\nQUnit.module( 'MobileFrontend WatchListGateway.js', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\too.setUp( sandbox, global );\n\t\tmediaWiki.setUp( sandbox, global );\n\n\t\t// needed for extendSearchParams to not throw exception about feature not\n\t\t// supporting wikibase descriptions in headless tests\n\t\tsandbox.stub( mw.config, 'get' )\n\t\t\t.withArgs( 'wgMFDisplayWikibaseDescriptions', {} )\n\t\t\t.returns( {\n\t\t\t\twatchlist: true\n\t\t\t} )\n\t\t\t// needed bc Page.js expects this call to return an array\n\t\t\t.withArgs( 'wgMFMobileFormatterHeadings', [ 'h1', 'h2', 'h3', 'h4', 'h5' ] )\n\t\t\t.returns( [ 'h1', 'h2', 'h3', 'h4', 'h5' ] );\n\t\t// needed for browser tests. If not stubbed, Page's newFromJSON() will call\n\t\t// mw.util.getUrl which calls mw.config.get and expects back a value\n\t\tsandbox.stub( mw.util, 'getUrl', function () {} );\n\n\t\tWatchListGateway = require( '../../../src/mobile.special.watchlist.scripts/WatchListGateway' );\n\t},\n\tafterEach: function () {\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( 'loadWatchlist() loads results from the first page', function ( assert ) {\n\tvar gateway = new WatchListGateway( new mw.Api() );\n\n\tsandbox.stub( mw.Api.prototype, 'get' )\n\t\t.returns( util.Deferred().resolve( response ) );\n\n\treturn gateway.loadWatchlist().then( function ( pages ) {\n\t\tvar params = mw.Api.prototype.get.firstCall.args[0];\n\n\t\tassert.strictEqual( params.continue, '', 'It should set the continue parameter' );\n\n\t\tassert.strictEqual( pages.length, 7, 'Got all the results' );\n\t\tassert.strictEqual( pages[0].displayTitle, 'Albert Einstein', 'Sorted alphabetically' );\n\t} );\n} );\n\nQUnit.test( 'loadWatchlist() loads results from the second page from last item of first', function ( assert ) {\n\tvar lastTitle = 'Albert Einstein',\n\t\tgateway = new WatchListGateway( new mw.Api(), lastTitle ),\n\t\tresponse1 = util.extend( {}, response, {\n\t\t\tcontinue: {\n\t\t\t\twatchlistraw: {\n\t\t\t\t\tgwrcontinue: '0|Albert Einstein'\n\t\t\t\t}\n\t\t\t}\n\t\t} ),\n\t\tstub;\n\n\t// First time we call the API for the second page\n\tstub = sandbox.stub( mw.Api.prototype, 'get' )\n\t\t.returns( util.Deferred().resolve( response1 ) );\n\n\treturn gateway.loadWatchlist().then( function ( pages ) {\n\t\tvar params = mw.Api.prototype.get.firstCall.args[0];\n\n\t\tassert.strictEqual( params.continue, 'gwrcontinue||', 'It should set the continue parameter' );\n\t\tassert.strictEqual( params.gwrcontinue, '0|Albert_Einstein', 'It should set the watchlistraw-specific continue parameter' );\n\n\t\t// Albert Einstein should not be in the results since it was the last\n\t\t// item in the first page.\n\t\tassert.strictEqual( pages.length, 6, 'Should have Albert removed from the results' );\n\t\tassert.strictEqual( pages[0].displayTitle, 'Anne Dallas Dudley', 'First item should be Anne' );\n\n\t\t// Let's call for the next page\n\t\tstub.returns( util.Deferred().resolve( response ) );\n\n\t\treturn gateway.loadWatchlist().then( function ( pages ) {\n\t\t\t// Albert Einstein should be the first result of the next page (not removed)\n\t\t\tassert.strictEqual( pages.length, 7, 'Albert should be in the results' );\n\t\t\tassert.strictEqual( pages[0].displayTitle, 'Albert Einstein', 'First item should be Albert' );\n\t\t} );\n\t} );\n} );\n\nQUnit.test( 'loadWatchlist() doesn\\'t throw an error when no pages are returned', function ( assert ) {\n\tvar gateway = new WatchListGateway( new mw.Api() );\n\n\tsandbox.stub( mw.Api.prototype, 'get' )\n\t\t.returns( util.Deferred().resolve( {\n\t\t\tbatchcomplete: ''\n\t\t} ) );\n\n\treturn gateway.loadWatchlist().then( function ( pages ) {\n\t\tassert.propEqual( pages, [] );\n\t} );\n} );\n\nQUnit.test( 'loadWatchlist() marks pages as new if necessary', function ( assert ) {\n\tvar gateway = new WatchListGateway( new mw.Api() );\n\n\tsandbox.stub( mw.Api.prototype, 'get' )\n\t\t.returns( util.Deferred().resolve( response ) );\n\n\treturn gateway.loadWatchlist().then( function ( pages ) {\n\t\tassert.strictEqual( pages[0].isMissing, false, 'Albert Einstein page isn\\'t marked as new' );\n\t\tassert.strictEqual( pages[6].isMissing, true, 'zzzz page is marked as new' );\n\t} );\n} );\n","/* global $ */\nvar\n\tBrowser = require( '../../../src/mobile.startup/Browser' ),\n\tdom = require( '../utils/dom' ),\n\tjQuery = require( '../utils/jQuery' ),\n\tsinon = require( 'sinon' ),\n\tmediawiki = require( '../utils/mw' ),\n\t$html;\n/** @type {sinon.SinonSandbox} */ var sandbox; // eslint-disable-line one-var\n\nQUnit.module( 'MobileFrontend Browser.js', {\n\tbeforeEach: function () {\n\t\tvar tmpDOM;\n\t\tsandbox = sinon.sandbox.create();\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\tmediawiki.setUp( sandbox, global );\n\t\t$html = $( tmpDOM );\n\t},\n\tafterEach: function () {\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( 'isIos()', function ( assert ) {\n\tvar browser = new Browser( 'Mozilla/5.0 (iPad; CPU OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko)', $html ),\n\t\tbrowser4 = new Browser( 'Mozilla/5.0 (iPad; CPU OS 4_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko)', $html ),\n\t\tbrowser5 = new Browser( 'Mozilla/5.0 (iPad; CPU OS 5_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko)', $html ),\n\t\tbrowser2 = new Browser( 'Mozilla/5.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/8.0 Mobile/11A465 Safari/9537.53', $html );\n\n\tassert.strictEqual( browser.isIos(), true );\n\tassert.strictEqual( browser.isIos( 8 ), false );\n\tassert.strictEqual( browser.isIos( 4 ), false );\n\tassert.strictEqual( browser.isIos( 5 ), false );\n\tassert.strictEqual( browser2.isIos(), true );\n\tassert.strictEqual( browser2.isIos( 8 ), true );\n\tassert.strictEqual( browser4.isIos( 4 ), true );\n\tassert.strictEqual( browser5.isIos( 5 ), true );\n} );\n\nQUnit.test( 'Methods are cached', function ( assert ) {\n\tvar ipad = new Browser( 'Mozilla/5.0 (iPad; CPU OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko)', $html ),\n\t\tiphone = new Browser( 'Mozilla/5.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/8.0 Mobile/11A465 Safari/9537.53', $html ),\n\t\tandroid2 = new Browser( 'Android 2', $html );\n\n\tfunction cache( obj, method ) {\n\t\treturn obj[ '__cache' + obj[ method ].cacheId ];\n\t}\n\n\t// Check that the same methods across different instances have their own\n\t// cache and don't interfere with one another\n\tassert.strictEqual( ipad.isIos(), true );\n\tassert.strictEqual( ipad.isIos( 8 ), false );\n\tassert.strictEqual( android2.isIos( 8 ), false );\n\tassert.strictEqual( iphone.isIos(), true );\n\tassert.strictEqual( iphone.isIos( 8 ), true );\n\n\t// Check that the caches have been filled\n\tassert.strictEqual( Object.keys( cache( ipad, 'isIos' ) ).length, 2, 'isIos on ipad cached as expected' );\n\tassert.strictEqual( Object.keys( cache( android2, 'isIos' ) ).length, 1, 'isIos on android cached as expected' );\n\tassert.strictEqual( Object.keys( cache( iphone, 'isIos' ) ).length, 2, 'isIos on iphone cached as expected' );\n} );\n\nQUnit.test( 'isWideScreen()', function ( assert ) {\n\tvar browser = new Browser( 'Mozilla/5.0 (iPad; CPU OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko)', $html );\n\tsandbox.stub( mw.config, 'get', function () {\n\t\treturn '720px';\n\t} );\n\tassert.strictEqual( browser.isWideScreen(), true );\n} );\n\nQUnit.test( 'supportsAnimations() - true', function ( assert ) {\n\tvar\n\t\tbrowser = new Browser( 'Mozilla/5.0 (iPad; CPU OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko)', $html ),\n\t\tstub = sandbox.stub( document, 'createElement', function () {\n\t\t\treturn {\n\t\t\t\tstyle: {\n\t\t\t\t\tanimationName: '',\n\t\t\t\t\ttransform: '',\n\t\t\t\t\ttransition: ''\n\t\t\t\t}\n\t\t\t};\n\t\t} ),\n\t\tresult;\n\n\t// Browser QUnit depends on a non-stubbed version of document.createElement\n\t// when showing the test result in the browser so we need to save the returned\n\t// value in an intermediate variable and manually restore the stub here before\n\t// calling assert.strictEqual\n\tresult = browser.supportsAnimations();\n\tstub.restore();\n\n\tassert.strictEqual( result, true );\n} );\n\nQUnit.test( 'supportsAnimations() - false', function ( assert ) {\n\tvar\n\t\tbrowser = new Browser( 'Mozilla/5.0 (iPad; CPU OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko)', $html ),\n\t\tstub = sandbox.stub( document, 'createElement', function () {\n\t\t\treturn {\n\t\t\t\tstyle: {}\n\t\t\t};\n\t\t} ),\n\t\tresult;\n\n\t// Browser QUnit depends on a non-stubbed version of document.createElement\n\t// when showing the test result in the browser so we need to save the returned\n\t// value in an intermediate variable and manually restore the stub here before\n\t// calling assert.strictEqual\n\tresult = browser.supportsAnimations();\n\tstub.restore();\n\n\tassert.strictEqual( result, false );\n} );\n\nQUnit.test( 'supportsTouchEvents()', function ( assert ) {\n\tvar browser = new Browser( 'Mozilla/5.0 (iPad; CPU OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko)', $html );\n\twindow.ontouchstart = window.ontouchstart || undefined;\n\tassert.strictEqual( browser.supportsTouchEvents(), true );\n} );\n\nQUnit.test( 'supportsGeoLocation()', function ( assert ) {\n\tvar browser = new Browser( 'Mozilla/5.0 (iPad; CPU OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko)', $html );\n\twindow.navigator.geolocation = window.navigator.geolocation || undefined;\n\tassert.strictEqual( browser.supportsGeoLocation(), true );\n} );\n","var\n\tsinon = require( 'sinon' ),\n\tdom = require( '../utils/dom' ),\n\tjQuery = require( '../utils/jQuery' ),\n\too = require( '../utils/oo' ),\n\tmediaWiki = require( '../utils/mw' ),\n\tButton,\n\tsandbox;\n\nQUnit.module( 'MobileFrontend Button.js', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\too.setUp( sandbox, global );\n\t\tmediaWiki.setUp( sandbox, global );\n\t\tButton = require( '../../../src/mobile.startup/Button' );\n\t},\n\tafterEach: function () {\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( 'creates a link if passed href option', function ( assert ) {\n\tvar\n\t\turl = 'https://www.foo.com',\n\t\tbutton = new Button( {\n\t\t\thref: url\n\t\t} );\n\n\tassert.strictEqual( button.$el[0].tagName, 'A' );\n\tassert.strictEqual( button.$el[0].getAttribute( 'href' ), 'https://www.foo.com' );\n} );\n\nQUnit.test( 'does not add href attribute when not a link', function ( assert ) {\n\tvar button = new Button( {\n\t\ttagName: 'div'\n\t} );\n\n\tassert.strictEqual( button.$el[0].tagName, 'DIV' );\n\tassert.strictEqual( button.$el[0].href, undefined );\n} );\n","/* eslint-env es6 */\nmodule.exports = {\n\tdefaultURLs: `\n\t\t<div class=\" drawer position-fixed view-border-box \">\n\t\t\t<div\n\t\t\t\tclass=\" mw-ui-icon mw-ui-icon-mf-arrow mw-ui-icon-element cancel \"\n\t\t\t\ttitle=\"\"\n\t\t\t> </div>\n\t\t\t<p> </p>\n\t\t\t<a href=\" logIn \" class=\" mw-ui-button mw-ui-progressive \">\n\t\t\t\tLog in\n\t\t\t</a>\n\t\t\t<div>\n\t\t\t\t<a href=\" signUp \" class=\" mw-ui-anchor mw-ui-progressive \">\n\t\t\t\t\tSign up\n\t\t\t\t</a>\n\t\t\t</div>\n\t\t</div>\n\t`,\n\toverrideURLs: `\n\t\t<div class=\" drawer position-fixed view-border-box \">\n\t\t\t<div\n\t\t\t\tclass=\" mw-ui-icon mw-ui-icon-mf-arrow mw-ui-icon-element cancel \"\n\t\t\t\ttitle=\"\"\n\t\t\t> </div>\n\t\t\t<p> </p>\n\t\t\t<a href=\" customLogIn \" class=\" mw-ui-button mw-ui-progressive \">\n\t\t\t\tcustom log in\n\t\t\t</a>\n\t\t\t<div>\n\t\t\t\t<a href=\" customSignUp \" class=\" mw-ui-anchor mw-ui-progressive \">\n\t\t\t\t\tcustom sign up\n\t\t\t\t</a>\n\t\t\t</div>\n\t\t</div>\n\t`\n};\n","var\n\t// Imports\n\tCtaDrawer,\n\tdom = require( '../utils/dom' ),\n\tAnchor,\n\tButton,\n\tDrawer,\n\tjQuery = require( '../utils/jQuery' ),\n\tmw = require( '../utils/mw' ),\n\too = require( '../utils/oo' ),\n\tsandbox,\n\tsinon = require( 'sinon' ),\n\n\t// Variables\n\tparent;\n\nQUnit.module( 'MobileFrontend CtaDrawer.js', {\n\tbeforeEach: function () {\n\t\tvar parentID = 'ctaDrawerParent';\n\n\t\tsandbox = sinon.sandbox.create();\n\n\t\t// Set up required by all Views.\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\too.setUp( sandbox, global );\n\n\t\t// Additional CtaDrawer global dependency.\n\t\tmw.setUp( sandbox, global );\n\n\t\t// Force consistent messaging between Special:JavaScriptTest and Node.js.\n\t\tsandbox.stub( global.mw, 'msg', function ( id ) {\n\t\t\tswitch ( id ) {\n\t\t\t\tcase 'mobile-frontend-watchlist-cta-button-login': return 'Log in';\n\t\t\t\tcase 'mobile-frontend-watchlist-cta-button-signup': return 'Sign up';\n\t\t\t}\n\t\t\treturn id;\n\t\t} );\n\t\tsandbox.stub( global.mw.util, 'getUrl', function ( pageName, params ) {\n\t\t\treturn params.type ? 'signUp' : 'logIn';\n\t\t} );\n\n\t\t// Dynamically import Views to use fresh sandboxed dependencies.\n\t\tAnchor = require( '../../../src/mobile.startup/Anchor' );\n\t\tButton = require( '../../../src/mobile.startup/Button' );\n\t\tDrawer = require( '../../../src/mobile.startup/Drawer' );\n\t\tCtaDrawer = require( '../../../src/mobile.startup/CtaDrawer' );\n\n\t\t// Rewire the prototype, not the instance, since this property is used during construction.\n\t\tsandbox.stub( Drawer.prototype, 'appendToElement', '#' + parentID );\n\n\t\t// Create a disposable host Element. See T209129.\n\t\tparent = document.createElement( 'div' );\n\t\tparent.id = parentID;\n\t\tdocument.documentElement.appendChild( parent );\n\t},\n\n\tafterEach: function () {\n\t\t// Discard host Element.\n\t\tdocument.documentElement.removeChild( parent );\n\t\tparent = undefined;\n\n\t\tCtaDrawer = undefined;\n\t\tDrawer = undefined;\n\t\tButton = undefined;\n\t\tAnchor = undefined;\n\n\t\tjQuery.tearDown();\n\n\t\tsandbox.restore();\n\t}\n}, function () {\n\tQUnit.module( 'redirectParams()', function () {\n\t\tQUnit.test( 'empty props, default URL', function ( assert ) {\n\t\t\tvar subject = CtaDrawer.prototype.test.redirectParams;\n\t\t\tsandbox.stub( global.mw.config, 'get', function () {\n\t\t\t\treturn 'pageName';\n\t\t\t} );\n\t\t\tassert.propEqual( subject( {} ), { returnto: 'pageName' } );\n\t\t} );\n\n\t\tQUnit.test( 'empty props, nondefault URL', function ( assert ) {\n\t\t\tvar subject = CtaDrawer.prototype.test.redirectParams;\n\t\t\tassert.propEqual( subject( {}, 'url' ), { returnto: 'url' } );\n\t\t} );\n\n\t\tQUnit.test( 'nonempty props', function ( assert ) {\n\t\t\tvar subject = CtaDrawer.prototype.test.redirectParams;\n\t\t\tassert.propEqual( subject( { key: 'val' }, 'url' ), {\n\t\t\t\tkey: 'val',\n\t\t\t\treturnto: 'url'\n\t\t\t} );\n\t\t} );\n\t} );\n\n\tQUnit.module( 'signUpParams()', function () {\n\t\tQUnit.test( 'empty props', function ( assert ) {\n\t\t\tvar subject = CtaDrawer.prototype.test.signUpParams;\n\t\t\tassert.propEqual( subject( {} ), { type: 'signup' } );\n\t\t} );\n\n\t\tQUnit.test( 'nonempty props', function ( assert ) {\n\t\t\tvar subject = CtaDrawer.prototype.test.signUpParams;\n\t\t\tassert.propEqual( subject( { key: 'val' } ), {\n\t\t\t\tkey: 'val',\n\t\t\t\ttype: 'signup'\n\t\t\t} );\n\t\t} );\n\t} );\n\n\tQUnit.module( 'HTML', function () {\n\t\tQUnit.test( 'defaults', function ( assert ) {\n\t\t\tvar\n\t\t\t\tsubject = new CtaDrawer(),\n\t\t\t\t// Import the expected HTML as a string and replace spaces with a \\s*. This allows\n\t\t\t\t// the HTML some flexibility in how it's rendered.\n\t\t\t\thtml = new RegExp( require( './CtaDrawer.test.html' ).defaultURLs.replace( /\\s+/g, '\\\\s*' ) );\n\n\t\t\tsinon.assert.match( subject.$el.get( 0 ).outerHTML, html );\n\t\t\tassert.ok( true );\n\t\t} );\n\n\t\tQUnit.test( 'overrides', function ( assert ) {\n\t\t\tvar\n\t\t\t\tsubject = new CtaDrawer( {\n\t\t\t\t\tprogressiveButton: new Button( {\n\t\t\t\t\t\tprogressive: true,\n\t\t\t\t\t\tlabel: 'custom log in',\n\t\t\t\t\t\thref: 'customLogIn'\n\t\t\t\t\t} ).options,\n\t\t\t\t\tactionAnchor: new Anchor( {\n\t\t\t\t\t\tprogressive: true,\n\t\t\t\t\t\tlabel: 'custom sign up',\n\t\t\t\t\t\thref: 'customSignUp'\n\t\t\t\t\t} ).options\n\t\t\t\t} ),\n\t\t\t\thtml = new RegExp( require( './CtaDrawer.test.html' ).overrideURLs.replace( /\\s+/g, '\\\\s*' ) );\n\n\t\t\tsinon.assert.match( subject.$el.get( 0 ).outerHTML, html );\n\t\t\tassert.ok( true );\n\t\t} );\n\t} );\n} );\n","var\n\t// Imports\n\tdom = require( '../utils/dom' ),\n\tDrawer,\n\tjQuery = require( '../utils/jQuery' ),\n\tmw = require( '../utils/mw' ),\n\too = require( '../utils/oo' ),\n\tsandbox,\n\tsinon = require( 'sinon' ),\n\tutil = require( '../../../src/mobile.startup/util' ),\n\n\t// Variables\n\tparent;\n\n// util.docReady() usage appears to be necessary over\n// `document.addEventListener('DOMContentLoaded', ...)` as the latter fires before the subject's\n// internal usage of the former.\n\nQUnit.module( 'MobileFrontend Drawer.js', {\n\tbeforeEach: function () {\n\t\tvar parentID = 'drawerParent';\n\n\t\tsandbox = sinon.sandbox.create();\n\n\t\t// Set up required by all Views.\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\too.setUp( sandbox, global );\n\n\t\t// Additional Drawer global dependency.\n\t\tmw.setUp( sandbox, global );\n\n\t\t// Dynamically import Drawer to use fresh sandboxed dependencies.\n\t\tDrawer = require( '../../../src/mobile.startup/Drawer' );\n\n\t\t// Rewire the prototype, not the instance, since this property is used during construction.\n\t\tsandbox.stub( Drawer.prototype, 'appendToElement', '#' + parentID );\n\n\t\t// Create a disposable host Element. See T209129.\n\t\tparent = document.createElement( 'div' );\n\t\tparent.id = parentID;\n\t\tdocument.documentElement.appendChild( parent );\n\t},\n\n\tafterEach: function () {\n\t\t// Discard host Element.\n\t\tdocument.documentElement.removeChild( parent );\n\t\tparent = undefined;\n\n\t\tDrawer = undefined;\n\n\t\tjQuery.tearDown();\n\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( 'appends self to parent when DOM is loaded', function ( assert ) {\n\tvar\n\t\tdone = assert.async(),\n\t\tsubject = new Drawer();\n\n\tutil.docReady( function () {\n\t\tassert.strictEqual( subject.$el.parent().get( 0 ), parent );\n\t\tdone();\n\t} );\n} );\n\nQUnit.test( 'adds class to parent when DOM is loaded', function ( assert ) {\n\tvar done = assert.async();\n\n\tnew Drawer(); // eslint-disable-line no-new\n\tutil.docReady( function () {\n\t\tassert.strictEqual( parent.className, 'has-drawer' );\n\t\tdone();\n\t} );\n} );\n\nQUnit.test( 'consumes clicks', function ( assert ) {\n\tvar\n\t\tdone = assert.async(),\n\t\tevent = new window.Event( 'click' ),\n\t\tsubject = new Drawer();\n\n\tevent.stopPropagation = function () {\n\t\tassert.ok( true );\n\t\tdone();\n\t};\n\tsubject.$el.get( 0 ).dispatchEvent( event );\n} );\n\nQUnit.test( 'visible on show()', function ( assert ) {\n\tvar\n\t\tdone = assert.async(),\n\t\tsubject = new Drawer();\n\n\tsubject.on( 'show', function () {\n\t\tassertVisible();\n\t\tassert.ok( true );\n\t\tdone();\n\t} );\n\n\tsubject.show();\n} );\n\nQUnit.test( 'hidden on hide()', function ( assert ) {\n\tvar\n\t\tdone = assert.async(),\n\t\tsubject = new Drawer();\n\n\tsubject.on( 'hide', function () {\n\t\tassertHidden();\n\t\tassert.ok( true );\n\t\tdone();\n\t} );\n\n\tsubject.hide();\n} );\n\nQUnit.test( 'hidden on click once presented', function ( assert ) {\n\tvar\n\t\tdone = assert.async(),\n\t\tsubject = new Drawer();\n\n\tsubject.on( 'hide', function () {\n\t\tassertHidden();\n\t\tassert.ok( true );\n\t\tdone();\n\t} );\n\n\tcallOnPresented( subject, function () {\n\t\tparent.click();\n\t} );\n\n\tsubject.show();\n} );\n\nQUnit.test( 'hidden on scroll once presented', function ( assert ) {\n\tvar\n\t\tdone = assert.async(),\n\t\tsubject = new Drawer();\n\n\tsubject.on( 'hide', function () {\n\t\tassertHidden();\n\t\tassert.ok( true );\n\t\tdone();\n\t} );\n\n\tcallOnPresented( subject, function () {\n\t\t// https://github.com/jsdom/jsdom/issues/1422\n\t\tvar event = new window.Event( 'scroll', { bubbles: true } );\n\t\tparent.dispatchEvent( event );\n\t} );\n\n\tsubject.show();\n} );\n\nQUnit.test( 'HTML is valid', function ( assert ) {\n\tvar subject = new Drawer(),\n\t\tdone = assert.async();\n\n\tutil.docReady( function () {\n\t\tassert.strictEqual(\n\t\t\tsubject.$el.get( 0 ).outerHTML, '<div class=\"drawer position-fixed view-border-box\"></div>'\n\t\t);\n\t\tdone();\n\t} );\n} );\n\n/**\n * @param {Drawer} subject\n * @param {Function} callback\n * @return {void}\n*/\nfunction callOnPresented( subject, callback ) {\n\t// Wait for appearance.\n\tsubject.on( 'show', function () {\n\t\t// Wait for minimum presentation duration to expire.\n\t\tsetTimeout( callback, subject.minHideDelay );\n\t} );\n}\n\nfunction assertVisible() {\n\tsinon.assert.match( parent.className, /.*\\bdrawer-visible\\b.*/ );\n}\n\nfunction assertHidden() {\n\tsinon.assert.match( parent.className, /^((?!\\bdrawer-visible\\b).)*$/ );\n}\n","var\n\tsinon = require( 'sinon' ),\n\tjQuery = require( '../utils/jQuery' ),\n\tmfExtend = require( '../../../src/mobile.startup/mfExtend' ),\n\tdom = require( '../utils/dom' ),\n\tmediaWiki = require( '../utils/mw' ),\n\too = require( '../utils/oo' ),\n\tutil = require( '../../../src/mobile.startup/util' ),\n\tHogan = require( 'hogan.js' ),\n\tOverlay,\n\tsandbox;\n\nQUnit.module( 'MobileFrontend: Overlay.js', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\too.setUp( sandbox, global );\n\t\tmediaWiki.setUp( sandbox, global );\n\t\tOverlay = require( '../../../src/mobile.startup/Overlay' );\n\n\t\t// jsdom will throw \"Not implemented\" errors if we don't stub\n\t\t// window.scrollTo\n\t\tsandbox.stub( global.window, 'scrollTo' );\n\n\t\t// Create a dummy mw-mf-viewport if none exists\n\t\tif ( !util.getDocument().find( '#mw-mf-viewport' ).length ) {\n\t\t\tthis.$viewport = util.parseHTML( '<div>' ).attr( 'id', 'mw-mf-viewport' ).appendTo( 'body' );\n\t\t}\n\t},\n\tafterEach: function () {\n\t\tif ( this.$viewport ) {\n\t\t\tthis.$viewport.remove();\n\t\t}\n\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( 'Simple overlay', function ( assert ) {\n\tvar overlay = new Overlay( {\n\t\t\theading: '<h2>Overlay Title</h2>'\n\t\t} ),\n\t\theadingNode;\n\n\theadingNode = overlay.$el.find( 'h2:contains(\"Overlay Title\")' );\n\n\tassert.strictEqual( headingNode.length, 1 );\n} );\n\nQUnit.test( '#make', function ( assert ) {\n\tvar overlay = Overlay.make( {\n\t\theading: 'Fresh from factory'\n\t}, new Overlay( {\n\t\tclassName: 'overlay-child',\n\t\theading: 'overlay in overlay'\n\t} ) );\n\n\tassert.strictEqual( overlay.$el.find( '.overlay-child' ).length, 1, 'there is an overlay in the overlay!' );\n\tassert.strictEqual(\n\t\toverlay.$el.find( '.overlay-title' ).eq( 0 ).text().trim(),\n\t\t'Fresh from factory',\n\t\t'First heading found'\n\t);\n\tassert.strictEqual(\n\t\toverlay.$el.find( '.overlay-content .overlay-title' ).text().trim(),\n\t\t'overlay in overlay',\n\t\t'Second heading found in overlay-content'\n\t);\n} );\n\nQUnit.test( 'HTML overlay', function ( assert ) {\n\tvar overlay;\n\n\tfunction TestOverlay() {\n\t\tOverlay.apply( this, arguments );\n\t}\n\n\tmfExtend( TestOverlay, Overlay, {\n\t\ttemplatePartials: util.extend( {}, Overlay.prototype.templatePartials, {\n\t\t\tcontent: Hogan.compile( '<div class=\"content\">YO</div>' )\n\t\t} )\n\t} );\n\toverlay = new TestOverlay( {\n\t\theading: 'Awesome'\n\t} );\n\n\tassert.strictEqual( overlay.$el.find( 'h2' ).html(), 'Awesome' );\n\tassert.strictEqual( overlay.$el.find( '.content' ).text(), 'YO' );\n} );\n\nQUnit.test( 'headerActions property', function ( assert ) {\n\tvar overlays = [\n\t\tnew Overlay( {} ),\n\t\tnew Overlay( {\n\t\t\theaderActions: [\n\t\t\t\t{ $el: util.parseHTML( '<div>' ) }\n\t\t\t]\n\t\t} ),\n\t\tnew Overlay( {\n\t\t\theaderButtons: [\n\t\t\t\t{\n\t\t\t\t\thref: '#',\n\t\t\t\t\tclassName: 'foo',\n\t\t\t\t\tdisabled: true,\n\t\t\t\t\tmsg: 'banana'\n\t\t\t\t}\n\t\t\t]\n\t\t} ),\n\t\tnew Overlay( {\n\t\t\theaderButtons: [\n\t\t\t\t{\n\t\t\t\t\thref: '#',\n\t\t\t\t\tclassName: 'foo',\n\t\t\t\t\tdisabled: true,\n\t\t\t\t\tmsg: 'banana'\n\t\t\t\t}\n\t\t\t],\n\t\t\theaderActions: [\n\t\t\t\t{ $el: util.parseHTML( '<div>' ) },\n\t\t\t\t{ $el: util.parseHTML( '<button>' ) }\n\t\t\t]\n\t\t} )\n\t];\n\tassert.strictEqual( overlays[0].$el.find( '.header-action' ).length, 0,\n\t\t'Overlays do not have header actions by default' );\n\tassert.strictEqual( overlays[1].$el.find( '.header-action > *' ).length, 1,\n\t\t'headerActions will be inserted into the header-action container' );\n\tassert.strictEqual( overlays[2].$el.find( '.header-action > *' ).length, 1,\n\t\t'headerButtons will be constructed from headerButtons into header-action container' );\n\tassert.strictEqual( overlays[3].$el.find( '.header-action > *' ).length, 3,\n\t\t'headerButtons and header actions can be mixed if necessary' );\n} );\n\nQUnit.test( 'onBeforeExit', function ( assert ) {\n\tvar spies = [],\n\t\toverlays = [\n\t\t\tnew Overlay( {} ),\n\t\t\tnew Overlay( {\n\t\t\t\tonBeforeExit: function () {}\n\t\t\t} ),\n\t\t\tnew Overlay( {\n\t\t\t\tonBeforeExit: function ( exit ) {\n\t\t\t\t\texit();\n\t\t\t\t}\n\t\t\t} )\n\t\t];\n\toverlays.forEach( function ( overlay ) {\n\t\tspies.push( sandbox.spy( overlay, 'hide' ) );\n\t\toverlay.onExitClick( new Event( 'click' ) );\n\t} );\n\tassert.strictEqual( spies[0].calledOnce, true, 'Overlay 1 hide method called' );\n\tassert.strictEqual( spies[1].calledOnce, false, 'Overlay 2 does not call the exit function' );\n\tassert.strictEqual( spies[2].calledOnce, true, 'Overlay 3 calls the exit function' );\n} );\n\nQUnit.test( 'Close overlay', function ( assert ) {\n\tvar overlay = new Overlay( {\n\t\theading: '<h2>Title</h2>',\n\t\tcontent: 'Text'\n\t} );\n\n\toverlay.show();\n\toverlay.hide();\n\n\tassert.strictEqual( overlay.$el[ 0 ].parentNode, null, 'No longer in DOM' );\n} );\n","/* global $ */\nvar\n\tsinon = require( 'sinon' ),\n\tdom = require( '../utils/dom' ),\n\tjQuery = require( '../utils/jQuery' ),\n\too = require( '../utils/oo' ),\n\tutil = require( '../../../src/mobile.startup/util' ),\n\tmediaWiki = require( '../utils/mw' ),\n\tOverlayManager, Overlay,\n\tfakeRouter,\n\toverlayManager,\n\trouteEvent,\n\tsandbox;\n\nQUnit.module( 'MobileFrontend mobile.startup/OverlayManager', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t\tdom.setUp( sandbox, global );\n\t\too.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\tmediaWiki.setUp( sandbox, global );\n\n\t\t// jsdom will throw \"Not implemented\" errors if we don't stub\n\t\t// window.scrollTo\n\t\tsandbox.stub( global.window, 'scrollTo' );\n\n\t\tOverlayManager = require( '../../../src/mobile.startup/OverlayManager' );\n\t\tOverlay = require( '../../../src/mobile.startup/Overlay' );\n\t\trouteEvent = function ( data ) {\n\t\t\treturn $.Event( 'route', data );\n\t\t};\n\n\t\tthis.createFakeOverlay = function ( options ) {\n\t\t\tvar fakeOverlay = new OO.EventEmitter();\n\t\t\tfakeOverlay.hasLoadError = false;\n\t\t\tfakeOverlay.show = sandbox.spy();\n\t\t\tfakeOverlay.hide = function () {\n\t\t\t\tthis.emit( 'hide' );\n\t\t\t\treturn true;\n\t\t\t};\n\t\t\tfakeOverlay.$el = util.parseHTML( '<div>' );\n\t\t\tsandbox.spy( fakeOverlay, 'hide' );\n\t\t\tutil.extend( fakeOverlay, options );\n\t\t\treturn fakeOverlay;\n\t\t};\n\n\t\tfakeRouter = new OO.EventEmitter();\n\t\tfakeRouter.getPath = sandbox.stub().returns( '' );\n\t\tfakeRouter.back = sandbox.spy();\n\t\tsandbox.stub( mw.loader, 'require' ).withArgs( 'mediawiki.router' ).returns( fakeRouter );\n\t\toverlayManager = new OverlayManager( fakeRouter, document.body );\n\t},\n\tafterEach: function () {\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( '#getSingleton', function ( assert ) {\n\tvar singleton = OverlayManager.getSingleton();\n\tassert.ok( singleton instanceof OverlayManager, 'singleton exists' );\n\tassert.strictEqual( singleton, OverlayManager.getSingleton(), 'same object returned each time' );\n} );\n\nQUnit.test( '#add', function ( assert ) {\n\tvar fakeOverlay = this.createFakeOverlay();\n\n\toverlayManager.add( /^test$/, function () {\n\t\treturn fakeOverlay;\n\t} );\n\tfakeRouter.emit( 'route', {\n\t\tpath: 'test'\n\t} );\n\n\tassert.strictEqual( fakeOverlay.show.callCount, 1, 'show registered overlay' );\n} );\n\nQUnit.test( '#show', function ( assert ) {\n\tvar fakeOverlay = this.createFakeOverlay(),\n\t\tshowSpy = sandbox.spy( overlayManager, '_show' );\n\n\toverlayManager.add( /^showTest$/, function () {\n\t\treturn fakeOverlay;\n\t} );\n\tfakeRouter.emit( 'route', {\n\t\tpath: 'showTest'\n\t} );\n\n\tassert.strictEqual( showSpy.callCount, 1, 'OverlayManager.show called on route change' );\n} );\n\nQUnit.test( '#add, with $.Deferred factory', function ( assert ) {\n\tvar deferred = util.Deferred(),\n\t\tfakeOverlay = this.createFakeOverlay();\n\tdeferred.show = sandbox.spy();\n\n\toverlayManager.add( /^foo$/, function () {\n\t\treturn deferred;\n\t} );\n\tfakeRouter.emit( 'route', {\n\t\tpath: 'foo'\n\t} );\n\tdeferred.resolve( fakeOverlay );\n\n\treturn deferred.then( function () {\n\t\tassert.notOk( deferred.show.called, 'don\\'t call show on Deferred' );\n\t\tassert.strictEqual( fakeOverlay.show.callCount, 1, 'show registered overlay' );\n\t} );\n} );\n\nQUnit.test( '#add, with current path', function ( assert ) {\n\tvar\n\t\tfakeOverlay = this.createFakeOverlay(),\n\t\tdeferred = util.Deferred();\n\tfakeRouter.getPath = sandbox.stub().returns( 'baha' );\n\n\toverlayManager.add( /^baha$/, function () {\n\t\treturn fakeOverlay;\n\t} );\n\n\t// Wait for $.ready because OverlayManager#add() does\n\tutil.docReady( function () {\n\t\tdeferred.resolve();\n\t} );\n\n\treturn deferred.then( function () {\n\t\tassert.strictEqual( fakeOverlay.show.callCount, 1, 'show registered overlay' );\n\t} );\n} );\n\nQUnit.test( '#replaceCurrent', function ( assert ) {\n\tvar fakeOverlay = this.createFakeOverlay(),\n\t\tanotherFakeOverlay = this.createFakeOverlay();\n\n\toverlayManager.add( /^test$/, function () {\n\t\treturn fakeOverlay;\n\t} );\n\n\tfakeRouter.emit( 'route', {\n\t\tpath: 'test'\n\t} );\n\toverlayManager.replaceCurrent( anotherFakeOverlay );\n\tassert.strictEqual( fakeOverlay.hide.callCount, 1, 'hide overlay' );\n\tassert.strictEqual( anotherFakeOverlay.show.callCount, 1, 'show another overlay' );\n\tfakeRouter.emit( 'route', {\n\t\tpath: ''\n\t} );\n\tassert.strictEqual( anotherFakeOverlay.hide.callCount, 1, 'hide another overlay' );\n} );\n\nQUnit.test( 'route with params', function ( assert ) {\n\tvar\n\t\tfakeOverlay = this.createFakeOverlay(),\n\t\tfactoryStub = sandbox.stub().returns( fakeOverlay );\n\n\toverlayManager.add( /^sam\\/(\\d+)$/, factoryStub );\n\tfakeRouter.emit( 'route', {\n\t\tpath: 'sam/123'\n\t} );\n\n\tassert.ok( factoryStub.calledWith( '123' ), 'pass params from the route' );\n} );\n\nQUnit.test( 'hide when route changes', function ( assert ) {\n\tvar\n\t\tfakeOverlay = this.createFakeOverlay(),\n\t\tfactoryStub = sandbox.stub().returns( fakeOverlay );\n\n\toverlayManager.add( /^jon$/, factoryStub );\n\tfakeRouter.emit( 'route', {\n\t\tpath: 'jon'\n\t} );\n\tfakeRouter.emit( 'route', {\n\t\tpath: ''\n\t} );\n\tfakeRouter.emit( 'route', {\n\t\tpath: 'jon'\n\t} );\n\tfakeRouter.emit( 'route', {\n\t\tpath: 'other'\n\t} );\n\n\tassert.strictEqual( fakeOverlay.hide.callCount, 2, 'hide overlay' );\n\tassert.ok( fakeOverlay.hide.getCall( 0 ).notCalledWith( true ), 'don\\'t force hide (first)' );\n\tassert.ok( fakeOverlay.hide.getCall( 1 ).notCalledWith( true ), 'don\\'t force hide (second)' );\n} );\n\nQUnit.test( 'go back (change route) if overlay hidden but not by route change', function ( assert ) {\n\tvar\n\t\tfakeOverlay = this.createFakeOverlay(),\n\t\tfactoryStub = sandbox.stub().returns( fakeOverlay );\n\n\toverlayManager.add( /^joakino$/, factoryStub );\n\tfakeRouter.emit( 'route', {\n\t\tpath: 'joakino'\n\t} );\n\tfakeOverlay.hide();\n\n\tassert.strictEqual( fakeRouter.back.callCount, 1, 'route back' );\n} );\n\nQUnit.test( 'Browser back can be overidden', function ( assert ) {\n\tvar escapableOverlay = new Overlay( {} ),\n\t\t$container = util.parseHTML( '<div>' ),\n\t\tcannotGoBackOverlay = new Overlay( {\n\t\t\tonBeforeExit: function () {}\n\t\t} ),\n\t\tmanager = new OverlayManager( fakeRouter, $container[ 0 ] );\n\n\t// define 2 routes\n\tmanager.add( /^proceed$/, function () {\n\t\treturn escapableOverlay;\n\t} );\n\tmanager.add( /^youcannotpass$/, function () {\n\t\treturn cannotGoBackOverlay;\n\t} );\n\tfakeRouter.emit( 'route', routeEvent( { path: 'proceed' } ) );\n\tassert.strictEqual( $container.find( escapableOverlay.$el ).length, 1,\n\t\t'escapable overlay is displayed' );\n\tfakeRouter.emit( 'route', routeEvent( { path: 'youcannotpass' } ) );\n\tassert.strictEqual( $container.find( escapableOverlay.$el ).length, 0,\n\t\t'escapable overlay is no longer displayed' );\n\tassert.strictEqual( $container.find( cannotGoBackOverlay.$el ).length, 1,\n\t\t'cannot go back overlay is now the overlay on display' );\n\t// attempt to go back\n\tfakeRouter.emit( 'route', routeEvent( { path: 'proceed' } ) );\n\tassert.strictEqual( $container.find( cannotGoBackOverlay.$el ).length, 1,\n\t\t'cannot go back overlay is still the overlay on display (cannot exit!)' );\n\tassert.strictEqual( $container.find( escapableOverlay.$el ).length, 0,\n\t\t'Escapeable overlay is not displayed' );\n\tassert.strictEqual( manager.stack[0].overlay, cannotGoBackOverlay,\n\t\t'Cannot go back overlay remains on the top of the stack' );\n} );\n\nQUnit.test( 'stacked overlays', function ( assert ) {\n\tvar\n\t\tfakeOverlay = this.createFakeOverlay(),\n\t\tfactoryStub = sandbox.stub().returns( fakeOverlay ),\n\t\tparentFakeOverlay = this.createFakeOverlay(),\n\t\tparentFactoryStub = sandbox.stub().returns( parentFakeOverlay );\n\n\toverlayManager.add( /^parent$/, parentFactoryStub );\n\toverlayManager.add( /^child$/, factoryStub );\n\n\tfakeRouter.emit( 'route', {\n\t\tpath: 'parent'\n\t} );\n\tassert.strictEqual( parentFakeOverlay.show.callCount, 1, 'show parent' );\n\tfakeRouter.emit( 'route', {\n\t\tpath: 'child'\n\t} );\n\tassert.strictEqual( parentFakeOverlay.hide.callCount, 1, 'hide parent' );\n\tassert.strictEqual( fakeOverlay.show.callCount, 1, 'show child' );\n\tfakeRouter.emit( 'route', {\n\t\tpath: 'parent'\n\t} );\n\tassert.strictEqual( fakeOverlay.hide.callCount, 1, 'hide child' );\n\tassert.strictEqual( parentFakeOverlay.show.callCount, 2, 'show parent again' );\n\n\tassert.strictEqual( parentFactoryStub.callCount, 1, 'create parent only once' );\n} );\n\nQUnit.test( 'prevent route change', function ( assert ) {\n\tvar\n\t\tfakeOverlay = this.createFakeOverlay( {\n\t\t\thide: sandbox.stub().returns( false )\n\t\t} ),\n\t\tfactoryStub = sandbox.stub().returns( fakeOverlay ),\n\t\tev = {\n\t\t\tpath: '',\n\t\t\tpreventDefault: sandbox.spy()\n\t\t};\n\n\toverlayManager.add( /^rob$/, factoryStub );\n\n\tfakeRouter.emit( 'route', {\n\t\tpath: 'rob'\n\t} );\n\tfakeRouter.emit( 'route', ev );\n\tassert.ok( ev.preventDefault.calledOnce, 'prevent route change' );\n} );\n\nQUnit.test( 'reload failed overlay when navigating to it again from another overlay', function ( assert ) {\n\tvar\n\t\tfailedOverlay = this.createFakeOverlay(),\n\t\tsuccessfulOverlay = this.createFakeOverlay(),\n\t\tfactoryStub,\n\t\tretryOverlayFn;\n\n\tfailedOverlay.hasLoadError = true;\n\tretryOverlayFn = sandbox.stub();\n\tretryOverlayFn.onCall( 0 ).returns( failedOverlay );\n\tretryOverlayFn.onCall( 1 ).returns( successfulOverlay );\n\tfactoryStub = function ( title ) {\n\t\tif ( title === '0' ) {\n\t\t\treturn retryOverlayFn();\n\t\t}\n\n\t\treturn successfulOverlay;\n\t};\n\n\toverlayManager.add( /^test\\/(\\d+)$/, factoryStub );\n\tfakeRouter.emit( 'route', {\n\t\tpath: 'test/0'\n\t} );\n\n\tassert.strictEqual( overlayManager.stack.length, 1, 'stack is correct size' );\n\tassert.ok( overlayManager.stack[0].overlay.hasLoadError, 'first overlay has load error' );\n\n\tfakeRouter.emit( 'route', {\n\t\tpath: 'test/1'\n\t} );\n\n\tassert.strictEqual( overlayManager.stack.length, 2, 'stack is correct size' );\n\tassert.notOk( overlayManager.stack[0].overlay.hasLoadError, 'second overlay loads successfully' );\n\n\tfakeRouter.emit( 'route', {\n\t\tpath: 'test/0'\n\t} );\n\n\tassert.strictEqual( overlayManager.stack.length, 1, 'stack decreases when going back to already visited overlay' );\n\tassert.notOk( overlayManager.stack[0].overlay.hasLoadError, 'Failed attempt is not cached and new overlay is loaded' );\n} );\n\nQUnit.test( 'replace overlay when route event path is equal to current path', function ( assert ) {\n\tvar\n\t\tfailedOverlay = this.createFakeOverlay(),\n\t\tsuccessfulOverlay = this.createFakeOverlay(),\n\t\tretryOverlayFn;\n\n\tfailedOverlay.hasLoadError = true;\n\tretryOverlayFn = sandbox.stub();\n\tretryOverlayFn.onCall( 0 ).returns( failedOverlay );\n\tretryOverlayFn.onCall( 1 ).returns( successfulOverlay );\n\n\toverlayManager.add( /^test\\/(\\d+)$/, retryOverlayFn );\n\tfakeRouter.emit( 'route', {\n\t\tpath: 'test/0'\n\t} );\n\n\tassert.strictEqual( overlayManager.stack.length, 1, 'stack is correct size' );\n\tassert.ok( overlayManager.stack[0].overlay.hasLoadError, 'overlay has load error' );\n\n\tfakeRouter.emit( 'route', {\n\t\tpath: 'test/0'\n\t} );\n\n\tassert.strictEqual( overlayManager.stack.length, 1, 'stack is correct size (did not increase upon reload)' );\n\tassert.notOk( overlayManager.stack[0].overlay.hasLoadError, 'overlay retry loads successfully' );\n} );\n","var\n\tdom = require( '../utils/dom' ),\n\tjQuery = require( '../utils/jQuery' ),\n\tmw = require( '../utils/mw' ),\n\too = require( '../utils/oo' ),\n\t// These both have heavy dependencies on jQuery so must be loaded later.\n\tPage, util,\n\tsinon = require( 'sinon' ),\n\tPARSER_OUTPUT = '<div class=\"mw-parser-output\">',\n\tMOBILE_TOC = '<div class=\"toc-mobile view-border-box\"><h2></h2><div></div></div>';\n/* eslint-disable one-var */\n/** @type {sinon.SinonSandbox} */ var sandbox;\n/** @type {typeof import('../../../src/mobile.startup/Page')} */ var stubPage;\n/** @type {typeof import('../../../src/mobile.startup/Page')} */ var mobileTocPage;\n/** @type {typeof import('../../../src/mobile.startup/Page')} */ var desktopPage;\n/** @type {typeof import('../../../src/mobile.startup/Page')} */ var sectionPage;\n/* eslint-enable one-var */\n\nQUnit.module( 'MobileFrontend Page', {\n\tbeforeEach: function () {\n\t\tvar ambox = function ( text ) {\n\t\t\t\treturn '<div class=\"ambox\">' + text + '</div>';\n\t\t\t},\n\t\t\tsectionHeading = function ( text ) {\n\t\t\t\treturn '<h2 class=\"section-heading\">' + text + '</h2>';\n\t\t\t},\n\t\t\tsectionSubHeading = function ( text, level ) {\n\t\t\t\tvar l = level || 'h3';\n\t\t\t\treturn '<' + l + '>' + text + '</' + l + '>';\n\t\t\t},\n\t\t\tsectionBody = function ( i, html ) {\n\t\t\t\treturn '<div class=\"mf-section-' + i + '\">' + html + '</div>';\n\t\t\t};\n\n\t\tsandbox = sinon.sandbox.create();\n\t\tdom.setUp( sandbox, global );\n\t\tmw.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\too.setUp( sandbox, global );\n\n\t\tPage = require( '../../../src/mobile.startup/Page' );\n\t\tutil = require( '../../../src/mobile.startup/util' );\n\n\t\tstubPage = new Page( {\n\t\t\tel: util.parseHTML( PARSER_OUTPUT ).html(\n\t\t\t\t'<p>lead</p>' + ambox( 'a0' )\n\t\t\t)\n\t\t} );\n\t\tmobileTocPage = new Page( {\n\t\t\tel: util.parseHTML( PARSER_OUTPUT ).html(\n\t\t\t\tsectionBody( 0, ambox( 'a0' ) + '<p>lead</p>' + MOBILE_TOC ) +\n\t\t\t\t// section = 1\n\t\t\t\tsectionHeading( '1' ) +\n\t\t\t\tsectionBody( 1,\n\t\t\t\t\tambox( 'a1' ) +\n\t\t\t\t\t// section = 2\n\t\t\t\t\tsectionSubHeading( '1.1' ) +\n\t\t\t\t\tambox( 'a1.1' )\n\t\t\t\t)\n\t\t\t)\n\t\t} );\n\t\tdesktopPage = new Page( {\n\t\t\tel: util.parseHTML( PARSER_OUTPUT ).html(\n\t\t\t\t'<p>lead</p>' +\n\t\t\t\tambox( 'a0' ) +\n\t\t\t\t// section = 1\n\t\t\t\tsectionSubHeading( '1', 'h2' ) +\n\t\t\t\tambox( 'a1' ) +\n\t\t\t\t// section = 2\n\t\t\t\tsectionSubHeading( '1.1' ) +\n\t\t\t\tambox( 'a1.1' )\n\t\t\t)\n\t\t} );\n\t\tsectionPage = new Page( {\n\t\t\tel: util.parseHTML( PARSER_OUTPUT ).html(\n\t\t\t\tsectionBody( 0, '<p>lead</p>' + ambox( 'a0' ) ) +\n\t\t\t\t// section = 1\n\t\t\t\tsectionHeading( '1' ) +\n\t\t\t\tsectionBody( 1,\n\t\t\t\t\tambox( 'a1' ) +\n\t\t\t\t\t// section = 2\n\t\t\t\t\tsectionSubHeading( '1.1' ) +\n\t\t\t\t\tambox( 'a1.1' ) +\n\t\t\t\t\t// section = 3\n\t\t\t\t\tsectionSubHeading( '1.1.1', 'h4' ) +\n\t\t\t\t\tambox( 'a1.1.1' ) +\n\t\t\t\t\t// section = 4\n\t\t\t\t\tsectionSubHeading( '1.1.2', 'h4' ) +\n\t\t\t\t\tambox( 'a1.1.2' ) +\n\t\t\t\t\t// section = 5\n\t\t\t\t\tsectionSubHeading( '1.2' ) +\n\t\t\t\t\tambox( 'a1.1' )\n\t\t\t\t) +\n\t\t\t\t// section = 6\n\t\t\t\tsectionHeading( '2' ) +\n\t\t\t\tsectionBody( 6,\n\t\t\t\t\tambox( 'a2' )\n\t\t\t\t) +\n\t\t\t\t// section 7\n\t\t\t\tsectionHeading( '3' ) +\n\t\t\t\tsectionBody( 7, ambox( 'a3' ) ) +\n\t\t\t\t// section 8\n\t\t\t\tsectionHeading( 'Section with nested Ambox' ) +\n\t\t\t\tsectionBody( 8,\n\t\t\t\t\tambox(\n\t\t\t\t\t\t'<p>nested-ambox-parent,</p>' +\n\t\t\t\t\t\tambox( 'nested-ambox-1,' ) +\n\t\t\t\t\t\tambox( 'nested-ambox-2' )\n\t\t\t\t\t) ) +\n\t\t\t\t// section 9\n\t\t\t\tsectionHeading( 'Sub-section with nested Ambox' ) +\n\t\t\t\t\tsectionBody( 9,\n\t\t\t\t\t\tambox(\n\t\t\t\t\t\t\t'<p>nested-ambox-parent,</p>' +\n\t\t\t\t\t\t\tambox( 'nested-ambox-1,' ) +\n\t\t\t\t\t\t\tambox( 'nested-ambox-2' )\n\t\t\t\t\t\t) +\n\t\t\t\t\t\t// section 10\n\t\t\t\t\t\tsectionSubHeading( 'subsection heading' ) +\n\t\t\t\t\t\t// section 11\n\t\t\t\t\t\tsectionSubHeading( 'Another subsection heading' )\n\t\t\t\t\t)\n\t\t\t) // end .html()\n\t\t} ); // end new Page();\n\t},\n\tafterEach: function () {\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( '#findInSectionLead', function ( assert ) {\n\t// check desktop page\n\t[\n\t\t[ 0, 'a0', 'lead section' ],\n\t\t[ 1, 'a1', 'h2' ],\n\t\t[ 2, 'a1.1', 'h3' ],\n\t\t[ 3, '', 'h4', 'selector does not match', '.foo' ],\n\t\t[ 111, '', 'Non-existent section' ]\n\t].forEach( function ( params, i ) {\n\t\tvar\n\t\t\tsection = params[0],\n\t\t\texpect = params[1],\n\t\t\ttest = params[2],\n\t\t\tselector = params[3] || '.ambox';\n\t\tassert.strictEqual(\n\t\t\tdesktopPage.findChildInSectionLead( section, selector ).text(),\n\t\t\texpect,\n\t\t\t'Found correct text in desktop test ' + i + ' case: ' + test\n\t\t);\n\t} );\n\t// check stub\n\t[\n\t\t[ 0, 'a0', 'lead section' ],\n\t\t[ 3, '', 'h4', 'selector does not match', '.foo' ],\n\t\t[ 111, '', 'Non-existent section' ]\n\t].forEach( function ( testcase ) {\n\t\tassert.strictEqual(\n\t\t\tstubPage.findChildInSectionLead( testcase[0], testcase[3] || '.ambox' ).text(),\n\t\t\ttestcase[1],\n\t\t\t'Stub: Found correct text in desktop test case:' + testcase[2]\n\t\t);\n\t} );\n\t// check mobile pages with section wrapping\n\t[\n\t\t[ 0, 'a0', 'lead section' ],\n\t\t[ 1, 'a1', 'h2' ],\n\t\t[ 2, 'a1.1', 'h3' ],\n\t\t[ 3, 'a1.1.1', 'h4' ],\n\t\t[ 3, '', 'h4', 'selector does not match', '.foo' ],\n\t\t[ 7, 'a3', 'h2 later' ],\n\t\t[ 111, '', 'Non-existent section' ]\n\t].forEach( function ( testcase ) {\n\t\tassert.strictEqual(\n\t\t\tsectionPage.findChildInSectionLead( testcase[0], testcase[3] || '.ambox' ).text(),\n\t\t\ttestcase[1],\n\t\t\t'Mobile: Found correct text in test case:' + testcase[2]\n\t\t);\n\t} );\n\t[\n\t\t[ 0, 'a0', 'lead section' ],\n\t\t[ 1, 'a1', 'h2' ],\n\t\t[ 2, 'a1.1', 'h3' ],\n\t\t[ 111, '', 'Non-existent section' ]\n\t].forEach( function ( testcase ) {\n\t\tassert.strictEqual(\n\t\t\tmobileTocPage.findChildInSectionLead( testcase[0], testcase[3] || '.ambox' ).text(),\n\t\t\ttestcase[1],\n\t\t\t'Mobile with table of contents: Found correct text in test case:' + testcase[2]\n\t\t);\n\t} );\n\n\t[\n\t\t[ 8, '.ambox', 'nested-ambox-parent,nested-ambox-1,nested-ambox-2', 'Nested elements in section' ],\n\t\t[ 9, '.ambox', 'nested-ambox-parent,nested-ambox-1,nested-ambox-2', 'Nested elements in subsection' ]\n\t].forEach( function ( testcase ) {\n\t\tvar result = sectionPage.findChildInSectionLead( testcase[0], testcase[1] );\n\t\tassert.strictEqual(\n\t\t\tresult.not( result.children() ).text(),\n\t\t\ttestcase[2],\n\t\t\t'Mobile: Found correct text in test case:' + testcase[3]\n\t\t);\n\t} );\n\n} );\n\nQUnit.test( '#isMainPage', function ( assert ) {\n\tvar p = new Page( {\n\t\t\ttitle: 'Main Page',\n\t\t\tisMainPage: true\n\t\t} ),\n\t\tp2 = new Page( {\n\t\t\ttitle: 'Foo'\n\t\t} );\n\tassert.strictEqual( p.isMainPage(), true, 'check main page flag is updated' );\n\tassert.strictEqual( p2.isMainPage(), false, 'check not marked as main page' );\n} );\n\nQUnit.test( '#getThumbnails', function ( assert ) {\n\tvar p, textPage, pLegacyUrls, thumbs, pNoViewer, pMetadata, pLazyImages, metadataTable,\n\t\tpLazyImagesTypo, pMetadataNested;\n\n\tp = new Page( {\n\t\tel: util.parseHTML( '<div><a href=\"/wiki/File:Cyanolimnas_cerverai_by_Allan_Brooks_cropped.jpg\" class=\"image view-border-box\"><img alt=\"Cyanolimnas cerverai by Allan Brooks cropped.jpg\" src=\"//upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Cyanolimnas_cerverai_by_Allan_Brooks_cropped.jpg/300px-Cyanolimnas_cerverai_by_Allan_Brooks_cropped.jpg\" width=\"300\" height=\"303\" data-file-width=\"454\" data-file-height=\"459\"></a></div>' )\n\t} );\n\ttextPage = new Page( {\n\t\tel: util.parseHTML( '<div></div>' )\n\t} );\n\tpLegacyUrls = new Page( {\n\t\tel: util.parseHTML( '<div><a href=\"/wikpa/index.php?title=File:Cyanolimnas_cerverai_by_Allan_Brooks_cropped.jpg\" class=\"image view-border-box\"><img alt=\"Cyanolimnas cerverai by Allan Brooks cropped.jpg\" src=\"//upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Cyanolimnas_cerverai_by_Allan_Brooks_cropped.jpg/300px-Cyanolimnas_cerverai_by_Allan_Brooks_cropped.jpg\" width=\"300\" height=\"303\" data-file-width=\"454\" data-file-height=\"459\"></a></div>' )\n\t} );\n\tthumbs = p.getThumbnails();\n\tpNoViewer = new Page( {\n\t\tel: util.parseHTML( '<div><a href=\"/wikpa/index.php?title=File:Cyanolimnas_cerverai_by_Allan_Brooks_cropped.jpg\" class=\"image view-border-box noviewer\"><img alt=\"Cyanolimnas cerverai by Allan Brooks cropped.jpg\" src=\"//upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Cyanolimnas_cerverai_by_Allan_Brooks_cropped.jpg/300px-Cyanolimnas_cerverai_by_Allan_Brooks_cropped.jpg\" width=\"300\" height=\"303\" data-file-width=\"454\" data-file-height=\"459\"></a></div>' )\n\t} );\n\tpMetadata = new Page( {\n\t\tel: util.parseHTML( '<div><a href=\"/wikpa/index.php?title=File:Cyanolimnas_cerverai_by_Allan_Brooks_cropped.jpg\" class=\"image view-border-box\"><img alt=\"Cyanolimnas cerverai by Allan Brooks cropped.jpg\" class=\"metadata\" src=\"//upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Cyanolimnas_cerverai_by_Allan_Brooks_cropped.jpg/300px-Cyanolimnas_cerverai_by_Allan_Brooks_cropped.jpg\" width=\"300\" height=\"303\" data-file-width=\"454\" data-file-height=\"459\"></a></div>' )\n\t} );\n\tpMetadataNested = new Page( {\n\t\tel: util.parseHTML( '<div class=\"noviewer\"><a href=\"/wikpa/index.php?title=File:Cyanolimnas_cerverai_by_Allan_Brooks_cropped.jpg\" class=\"image view-border-box\"><img alt=\"Cyanolimnas cerverai by Allan Brooks cropped.jpg\" src=\"//upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Cyanolimnas_cerverai_by_Allan_Brooks_cropped.jpg/300px-Cyanolimnas_cerverai_by_Allan_Brooks_cropped.jpg\" width=\"300\" height=\"303\" data-file-width=\"454\" data-file-height=\"459\"></a></div>' )\n\t} );\n\tpLazyImages = new Page( {\n\t\tel: util.parseHTML( '<div><a href=\"/wiki/File:Design_portal_logo.jpg\" class=\"image\"><span class=\"lazy-image-placeholder\" style=\"width: 28px;height: 28px;\" data-src=\"//upload.wikimedia.org/wikipedia/commons/thumb/3/3b/Design_portal_logo.jpg/28px-Design_portal_logo.jpg\" data-alt=\"icon\" data-width=\"28\" data-height=\"28\" data-class=\"noviewer\">&nbsp;</span></a></div>' )\n\t} );\n\tpLazyImagesTypo = new Page( {\n\t\tel: util.parseHTML( '<div><a href=\"/wiki/File:Design_portal_logo.jpg\" class=\"image\"><span class=\"lazy-image-placeholder\" style=\"width: 28px;height: 28px;\" data-src=\"//upload.wikimedia.org/wikipedia/commons/thumb/3/3b/Design_portal_logo.jpg/28px-Design_portal_logo.jpg\" data-alt=\"icon\" data-width=\"28\" data-height=\"28\" data-class=\"wot noviewerz bar\">&nbsp;</span></a></div>' )\n\t} );\n\tmetadataTable = new Page( {\n\t\tel: util.parseHTML( '<div><table class=\"plainlinks metadata ambox ambox-content ambox-Unreferenced\" role=\"presentation\"><tr><td class=\"mbox-image\"><div style=\"width:52px\"><a href=\"/wiki/File:Question_book-new.svg\" class=\"image\"><span class=\"lazy-image-placeholder\" style=\"width: 50px;height: 39px;\" data-src=\"https://upload.wikimedia.org/wikipedia/commons/thumb/9/99/Question_book-new.svg/50px-Question_book-new.svg.png\" data-alt=\"\" data-width=\"50\" data-height=\"39\" data-srcset=\"https://upload.wikimedia.org/wikipedia/commons/thumb/9/99/Question_book-new.svg/75px-Question_book-new.svg.png 1.5x, https://upload.wikimedia.org/wikipedia/commons/thumb/9/99/Question_book-new.svg/100px-Question_book-new.svg.png 2x\"> </span></a></div></td></tr></table>' )\n\t} );\n\n\tassert.strictEqual( thumbs.length, 1, 'Found expected number of thumbnails.' );\n\tassert.strictEqual( thumbs[0].getFileName(), 'File:Cyanolimnas_cerverai_by_Allan_Brooks_cropped.jpg',\n\t\t'Found expected filename.' );\n\n\tthumbs = textPage.getThumbnails();\n\tassert.strictEqual( thumbs.length, 0, 'This page has no thumbnails.' );\n\n\tthumbs = pLegacyUrls.getThumbnails();\n\tassert.strictEqual( thumbs.length, 1, 'Found expected number of thumbnails.' );\n\tassert.strictEqual( thumbs[0].getFileName(), 'File:Cyanolimnas_cerverai_by_Allan_Brooks_cropped.jpg',\n\t\t'Found expected filename.' );\n\n\tthumbs = pNoViewer.getThumbnails();\n\tassert.strictEqual( thumbs.length, 0, 'This page has no thumbnails.' );\n\n\tthumbs = pMetadata.getThumbnails();\n\tassert.strictEqual( thumbs.length, 0, 'This page has no thumbnails.' );\n\n\tthumbs = pMetadataNested.getThumbnails();\n\tassert.strictEqual( thumbs.length, 0,\n\t\t'Images inside a container with the class are not included. Images inside tables for example.' );\n\n\tthumbs = pLazyImages.getThumbnails();\n\tassert.strictEqual( thumbs.length, 0,\n\t\t'Consider whether the class is on an image which has not been lazy loaded.' );\n\n\tthumbs = metadataTable.getThumbnails();\n\tassert.strictEqual( thumbs.length, 0,\n\t\t'Consider whether the lazy loaded image is inside a .metadata container.' );\n\n\tthumbs = pLazyImagesTypo.getThumbnails();\n\tassert.strictEqual( thumbs.length, 1,\n\t\t'Thumbnail found if there is a typo.' );\n} );\n\nQUnit.test( '#getNamespaceId', function ( assert ) {\n\tvar testCases = [\n\t\t[ 'Main Page', 0 ],\n\t\t[ 'San Francisco', 0 ],\n\t\t[ 'San Francisco: Talk:2', 0 ],\n\t\t[ 'San Francisco: The Sequel', 0 ],\n\t\t[ 'Talk:Foo', 1 ],\n\t\t[ 'Project:Bar', 4 ],\n\t\t[ 'User talk:Jon', 3 ],\n\t\t[ 'Special:Nearby', -1 ]\n\t];\n\ttestCases.forEach( function ( tc ) {\n\t\tvar p = new Page( {\n\t\t\ttitle: tc[ 0 ]\n\t\t} );\n\t\tassert.strictEqual( p.getNamespaceId(), tc[ 1 ], 'Check namespace is as expected' );\n\t} );\n} );\n\nQUnit.test( '#isTalkPage', function ( assert ) {\n\tvar testCases = [\n\t\t[ 'Main Page', false ],\n\t\t[ 'San Francisco', false ],\n\t\t[ 'San Francisco: Talk:2', false ],\n\t\t[ 'San Francisco: The Sequel', false ],\n\t\t[ 'Talk:Foo', true ],\n\t\t[ 'Project talk:Bar', true ],\n\t\t[ 'User talk:Jon', true ],\n\t\t[ 'Special:Nearby', false ]\n\t];\n\ttestCases.forEach( function ( tc ) {\n\t\tvar p = new Page( {\n\t\t\ttitle: tc[ 0 ]\n\t\t} );\n\t\tassert.strictEqual( p.isTalkPage(), tc[ 1 ], 'Check test is as expected' );\n\t} );\n} );\n\nQUnit.test( '#isMissing', function ( assert ) {\n\tvar missing, notMissing;\n\tmissing = [\n\t\tnew Page( {\n\t\t\ttitle: 'Hello',\n\t\t\tid: 0\n\t\t} ),\n\t\tnew Page( {\n\t\t\ttitle: 'Hello',\n\t\t\tid: 5,\n\t\t\tisMissing: true\n\t\t} ),\n\t\tnew Page( {\n\t\t\ttitle: 'Hello',\n\t\t\tisMissing: true\n\t\t} )\n\t];\n\tnotMissing = [\n\t\tnew Page( {\n\t\t\ttitle: 'Hello',\n\t\t\tid: 4\n\t\t} ),\n\t\tnew Page( {\n\t\t\ttitle: 'Hello',\n\t\t\tid: 4,\n\t\t\tisMissing: false\n\t\t} ),\n\t\tnew Page( {\n\t\t\ttitle: 'Hello',\n\t\t\tisMissing: false\n\t\t} ),\n\t\tnew Page( {\n\t\t\ttitle: 'Hello',\n\t\t\tid: 0,\n\t\t\tisMissing: false\n\t\t} )\n\t];\n\tmissing.forEach( function ( page, i ) {\n\t\tassert.strictEqual( page.isMissing, true, 'page ' + i + ' is missing' );\n\t} );\n\tnotMissing.forEach( function ( page, i ) {\n\t\tassert.strictEqual( page.isMissing, false, 'page ' + i + ' is not missing' );\n\t} );\n} );\n\nQUnit.test( '#allowsXSS', function ( assert ) {\n\tvar p = new Page( {\n\t\t\ttitle: '<script>alert(\"oops, XSS possible!\");</script>'\n\t\t} ),\n\t\ttitleJSON = [\n\t\t\t{\n\t\t\t\tthumbnail: false,\n\t\t\t\ttitle: '<script>alert(\"oops, XSS possible!\");</script>',\n\t\t\t\tterms: false,\n\t\t\t\ttestDesc: 'Check against XSS in Page.newFromJSON displaytitle (when title set)'\n\t\t\t},\n\t\t\t{\n\t\t\t\tthumbnail: false,\n\t\t\t\tpageprops: [],\n\t\t\t\tterms: {\n\t\t\t\t\tlabel: [\n\t\t\t\t\t\t'<script>alert(\"oops, XSS possible!\");</script>'\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\ttestDesc: 'Check against XSS in Page.newFromJSON displaytitle (when Wikibase label set)'\n\t\t\t}\n\t\t];\n\n\tassert.strictEqual(\n\t\tp.getDisplayTitle(),\n\t\t'&lt;script&gt;alert(&quot;oops, XSS possible!&quot;);&lt;/script&gt;',\n\t\t'Check against XSS in Page.js constructor displaytitle (when title set)'\n\t);\n\n\ttitleJSON.forEach( function ( json ) {\n\t\tp = Page.newFromJSON( json );\n\n\t\tassert.strictEqual(\n\t\t\tp.getDisplayTitle(),\n\t\t\t'&lt;script&gt;alert(&quot;oops, XSS possible!&quot;);&lt;/script&gt;',\n\t\t\tjson.testDesc\n\t\t);\n\t} );\n} );\n","var util,\n\tsinon = require( 'sinon' ),\n\tdom = require( '../utils/dom' ),\n\tmediawiki = require( '../utils/mw' ),\n\too = require( '../utils/oo' ),\n\tjQuery = require( '../utils/jQuery' ),\n\texamples = require( './../utils/PageInputs.html' ),\n\tpage = examples.page,\n\tpage2 = examples.page2,\n\ttestData = require( '../utils/PageGateway.responses' ),\n\tPageGateway,\n\tpageGateway,\n\tsandbox;\n\nQUnit.module( 'MobileFrontend PageGateway', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\tmediawiki.setUp( sandbox, global );\n\t\too.setUp( sandbox, global );\n\t\tutil = require( '../../../src/mobile.startup/util' );\n\t\tPageGateway = require( '../../../src/mobile.startup/PageGateway' );\n\t\tthis.api = new mw.Api();\n\t\tpageGateway = new PageGateway( this.api );\n\t},\n\tafterEach: function () {\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( '#getSections (has sections)', function ( assert ) {\n\tvar gateway = new PageGateway();\n\tsandbox.stub( gateway, 'getPage' ).returns(\n\t\tutil.Deferred().resolve( {\n\t\t\tsections: [ { line: '1' } ]\n\t\t} )\n\t);\n\treturn gateway.getSections( gateway, 'Title' ).then( function ( sections ) {\n\t\tassert.strictEqual( sections.length, 1, '1 section is returned' );\n\t} );\n} );\n\nQUnit.test( '#getSections (missing titles)', function ( assert ) {\n\tvar gateway = new PageGateway();\n\tsandbox.stub( gateway, 'getPage' ).returns(\n\t\tutil.Deferred().reject( 'missingtitle' )\n\t);\n\treturn gateway.getSections( gateway, 'Title' ).then( function ( sections ) {\n\t\tassert.strictEqual( sections.length, 0, '0 sections are returned' );\n\t} );\n} );\n\nQUnit.test( '#getSections (other failures)', function ( assert ) {\n\tvar gateway = new PageGateway();\n\tsandbox.stub( gateway, 'getPage' ).returns(\n\t\tutil.Deferred().reject()\n\t);\n\tassert.throws( gateway.getSections( gateway, 'Title' ), 'an exception is thrown' );\n} );\n\nQUnit.test( '#getPage (h1s)', function ( assert ) {\n\n\tsandbox.stub( this.api, 'get' ).returns( util.Deferred().resolve( testData.getPageHeadings.input ) );\n\tpageGateway.invalidatePage( 'Test' );\n\n\tsandbox.stub( mw.util, 'getUrl' ).returns( 'Test:History' );\n\n\treturn pageGateway.getPage( 'Test' ).then( function ( resp ) {\n\t\tassert.propEqual( resp, testData.getPageHeadings.output, 'return lead and sections test 1' );\n\t} );\n} );\n\nQUnit.test( '#getPage', function ( assert ) {\n\tvar api = sandbox.stub( this.api, 'get' ).returns( util.Deferred().resolve( testData.getPage.input ) );\n\n\tsandbox.stub( mw.util, 'getUrl' ).returns( 'Test:History' );\n\n\tpageGateway.invalidatePage( 'Test' );\n\treturn pageGateway.getPage( 'Test' ).then( function ( resp ) {\n\t\tassert.propEqual( resp, testData.getPage.output, 'return lead and sections test 2' );\n\n\t\treturn pageGateway.getPage( 'Test' );\n\t} ).then( function () {\n\t\tassert.strictEqual( api.callCount, 1, 'cache page' );\n\t} );\n} );\n\nQUnit.test( '#getPageLanguages (response)', function ( assert ) {\n\tsandbox.stub( this.api, 'get' ).returns( util.Deferred().resolve( testData.getPageLanguagesResponse.input ) );\n\n\treturn pageGateway.getPageLanguages( 'Test' ).then( function ( resp ) {\n\t\tassert.propEqual( resp.languages,\n\t\t\ttestData.getPageLanguagesResponse.output.languages,\n\t\t\t'return augmented language links' );\n\n\t\tassert.propEqual( resp.variants,\n\t\t\ttestData.getPageLanguagesResponse.output.variants,\n\t\t\t'return augmented language variant links' );\n\t} );\n} );\n\nQUnit.test( '#getPageLanguages (call)', function ( assert ) {\n\tvar spy = sandbox.stub( this.api, 'get' ).returns( util.Deferred().reject() );\n\t// prevent rogue ajax request\n\t// eslint-disable-next-line no-undef\n\tsandbox.stub( $, 'ajax' ).returns( util.Deferred().resolve() );\n\tpageGateway.getPageLanguages( 'Title', 'fr' );\n\tassert.ok(\n\t\tspy.calledWith( testData.getPageLanguagesCall.output )\n\t);\n} );\n\nQUnit.test( '#_getAPIResponseFromHTML', function ( assert ) {\n\tvar resp = pageGateway._getAPIResponseFromHTML(\n\t\tutil.parseHTML( page )\n\t);\n\tassert.propEqual( testData.getAPIResponseFromHTML.input, resp );\n} );\n\nQUnit.test( '#getSectionsFromHTML malformed (h2 before h1)', function ( assert ) {\n\tvar resp = pageGateway.getSectionsFromHTML(\n\t\tutil.parseHTML( page2 )\n\t);\n\tassert.propEqual( resp, [\n\t\t{\n\t\t\tline: 'A1',\n\t\t\tlevel: '2',\n\t\t\tanchor: '1.0',\n\t\t\ttext: '<h3 id=\"\">A2.1</h3>\\n\\n',\n\t\t\tsubsections: [ {\n\t\t\t\tline: 'A2.1',\n\t\t\t\tlevel: '3',\n\t\t\t\tanchor: '',\n\t\t\t\ttext: '',\n\t\t\t\tsubsections: []\n\t\t\t} ]\n\t\t},\n\t\t{\n\t\t\tline: 'A2.2',\n\t\t\tlevel: '2',\n\t\t\tanchor: '',\n\t\t\ttext: '',\n\t\t\tsubsections: []\n\t\t},\n\t\t{\n\t\t\tline: 'A2',\n\t\t\tlevel: '1',\n\t\t\tanchor: '',\n\t\t\ttext: '<h2 id=\"\">A2.1</h2>\\n\\n',\n\t\t\tsubsections: [ {\n\t\t\t\tline: 'A2.1',\n\t\t\t\tlevel: '2',\n\t\t\t\tanchor: '',\n\t\t\t\ttext: '',\n\t\t\t\tsubsections: []\n\t\t\t} ]\n\t\t}\n\t] );\n} );\n\nQUnit.test( '#getPage (forwards api errors)', function ( assert ) {\n\tsandbox.stub( this.api, 'get' ).returns( util.Deferred().reject( 'missingtitle' ) );\n\treturn pageGateway.getPage( 'Err' ).catch( function ( msg ) {\n\t\tassert.strictEqual( msg, 'missingtitle' );\n\t} );\n} );\n\nQUnit.test( '#getPage (move protected page)', function ( assert ) {\n\tvar expected = {\n\t\tedit: [ '*' ],\n\t\tmove: [ 'sysop' ]\n\t};\n\tsandbox.stub( this.api, 'get' ).returns( util.Deferred().resolve( {\n\t\tmobileview: {\n\t\t\tid: -1,\n\t\t\tdisplaytitle: 'Test',\n\t\t\trevId: 42,\n\t\t\tlastmodifiedby: {\n\t\t\t\tname: 'bob',\n\t\t\t\tgender: 'unknown'\n\t\t\t},\n\t\t\tprotection: {\n\t\t\t\tmove: [ 'sysop' ]\n\t\t\t},\n\t\t\tlastmodified: '2013-10-28T18:49:56Z',\n\t\t\tlanguagecount: 10,\n\t\t\tsections: [\n\t\t\t\t{\n\t\t\t\t\tid: 0,\n\t\t\t\t\ttext: ''\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t} ) );\n\n\tpageGateway.invalidatePage( 'Test' );\n\treturn pageGateway.getPage( 'Test' ).then( function ( resp ) {\n\t\tassert.propEqual( resp.protection, expected );\n\t} );\n} );\n","var\n\tsinon = require( 'sinon' ),\n\tdom = require( '../utils/dom' ),\n\tjQuery = require( '../utils/jQuery' ),\n\tmediaWiki = require( '../utils/mw' ),\n\too = require( '../utils/oo' ),\n\tPanel,\n\tsandbox;\n\nQUnit.module( 'MobileFrontend Panel.js', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\too.setUp( sandbox, global );\n\t\tmediaWiki.setUp( sandbox, global );\n\t\tPanel = require( '../../../src/mobile.startup/Panel' );\n\t},\n\tafterEach: function () {\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( 'show() when not visible', function ( assert ) {\n\tvar\n\t\tdone = assert.async(),\n\t\tpanel = new Panel();\n\n\tpanel.on( 'show', function () {\n\t\tassert.ok( panel.$el.hasClass( 'visible' ), 'Visible class is set' );\n\t\tassert.ok( panel.$el.hasClass( 'animated' ), 'Animated class is set' );\n\t\tdone();\n\t} );\n\n\tpanel.show();\n} );\n\nQUnit.test( 'hide() when visible', function ( assert ) {\n\tvar\n\t\tdone = assert.async(),\n\t\tpanel = new Panel();\n\n\tpanel.on( 'hide', function () {\n\t\tassert.notOk( panel.$el.hasClass( 'visible', 'Visible class is removed' ) );\n\t\tdone();\n\t} );\n\n\tpanel.show();\n\tpanel.hide();\n} );\n\nQUnit.test( 'isVisible() when visible', function ( assert ) {\n\tvar\n\t\tdone = assert.async(),\n\t\tpanel = new Panel();\n\n\tpanel.on( 'show', function () {\n\t\tassert.ok( panel.isVisible(), 'Returns true when visible' );\n\t\tdone();\n\t} );\n\n\tpanel.show();\n} );\n\nQUnit.test( 'isVisible() when not visible', function ( assert ) {\n\tvar panel = new Panel();\n\n\tassert.notOk( panel.isVisible(), 'Returns false when not visible' );\n} );\n\nQUnit.test( 'onCancel()', function ( assert ) {\n\tvar\n\t\tdone = assert.async(),\n\t\tpanel = new Panel();\n\n\tpanel.on( 'hide', function () {\n\t\tassert.notOk( panel.$el.hasClass( 'visible' ), 'Removes visible class' );\n\t\tdone();\n\t} );\n\n\tpanel.show();\n\tpanel.onCancel( {\n\t\tpreventDefault: function () {}\n\t} );\n} );\n\nQUnit.test( 'toggle()', function ( assert ) {\n\tvar\n\t\tdone = assert.async(),\n\t\tpanel = new Panel();\n\n\tpanel.on( 'show', function () {\n\t\tassert.ok( panel.isVisible(), 'Shows panel when not visible' );\n\t\tpanel.toggle();\n\t} );\n\n\tpanel.on( 'hide', function () {\n\t\tassert.notOk( panel.isVisible(), 'Hides panel when visible' );\n\t\tdone();\n\t} );\n\n\tpanel.toggle();\n} );\n","var\n\tsinon = require( 'sinon' ),\n\too = require( '../utils/oo' ),\n\tsandbox,\n\tScrollEndEventEmitter;\n\nQUnit.module( 'MobileFrontend ScrollEndEventEmitter.js', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t\too.setUp( sandbox, global );\n\n\t\tScrollEndEventEmitter = require( '../../../src/mobile.startup/ScrollEndEventEmitter' );\n\t},\n\tafterEach: function () {\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( 'initializes properly', function ( assert ) {\n\tvar\n\t\teventBus = {\n\t\t\ton: sinon.spy()\n\t\t},\n\t\tis = new ScrollEndEventEmitter( eventBus, 500 ),\n\t\tis2 = new ScrollEndEventEmitter( eventBus );\n\n\tassert.strictEqual( is.enabled, true,\n\t\t'Emission is enabled by default' );\n\tassert.strictEqual( is.threshold, 500, 'Threshold is saved' );\n\tassert.strictEqual( is2.threshold, 100,\n\t\t'Without a threshold we get a default' );\n\tassert.strictEqual( eventBus.on.withArgs( 'scroll:throttled',\n\t\tis._scrollHandler ).calledOnce, true, 'Scrolling handler is bound' );\n} );\n\nQUnit.test( 'emits scroll end event', function ( assert ) {\n\tvar\n\t\teventBus = {\n\t\t\ton: function ( _, handler ) {\n\t\t\t\tthis.handler = handler;\n\t\t\t},\n\t\t\toff: function () {}\n\t\t},\n\t\tis = new ScrollEndEventEmitter( eventBus );\n\n\t// stub scrollNearEnd method because headless tests don't support scrolling\n\tsandbox.stub( is, 'scrollNearEnd' ).returns( true );\n\tis.setElement( {} );\n\n\tis.on( ScrollEndEventEmitter.EVENT_SCROLL_END, function () {\n\t\tassert.ok( true, 'scroll end event emitted' );\n\t} );\n\t// trigger stubbed 'scroll:throttled' event\n\teventBus.handler();\n} );\n\nQUnit.test( 'doesn\\'t emit when disabled', function ( assert ) {\n\tvar\n\t\temitSpy = sandbox.spy( ScrollEndEventEmitter.prototype, 'emit' ),\n\t\teventBus = {\n\t\t\ton: function ( _, handler ) {\n\t\t\t\tthis.handler = handler;\n\t\t\t},\n\t\t\toff: function () {}\n\t\t},\n\t\tis = new ScrollEndEventEmitter( eventBus );\n\tis.setElement( {} );\n\tis.disable();\n\n\t// trigger stubbed 'scroll:throttled' event\n\teventBus.handler();\n\tassert.strictEqual( emitSpy.called, false, 'emit should not be called' );\n} );\n","var\n\tsinon = require( 'sinon' ),\n\tdom = require( '../utils/dom' ),\n\tjQuery = require( '../utils/jQuery' ),\n\too = require( '../utils/oo' ),\n\tSection,\n\tsandbox;\n\nQUnit.module( 'MobileFrontend Section.js', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\too.setUp( sandbox, global );\n\t\tSection = require( '../../../src/mobile.startup/Section' );\n\t},\n\tafterEach: function () {\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( 'initialize with options', function ( assert ) {\n\tvar section = new Section( {\n\t\tlevel: '1',\n\t\tline: 'Line',\n\t\ttext: 'Text',\n\t\thasReferences: true,\n\t\tid: 'ID',\n\t\tanchor: 'Anchor'\n\t} );\n\n\tassert.strictEqual( section.line, 'Line', 'line is set' );\n\tassert.strictEqual( section.text, 'Text', 'text is set' );\n\tassert.strictEqual( section.hasReferences, true, 'hasReferences is set' );\n\tassert.strictEqual( section.id, 'ID', 'id is set' );\n\tassert.strictEqual( section.anchor, 'Anchor', 'anchor is set' );\n\tassert.strictEqual( section.subsections.length, 0, 'Subsections are empty' );\n} );\n\nQUnit.test( 'initialize with subsections', function ( assert ) {\n\tvar\n\t\tsection = new Section( {\n\t\t\tsubsections: [ {\n\t\t\t\tlevel: '',\n\t\t\t\tline: 'Line',\n\t\t\t\ttext: 'Text',\n\t\t\t\thasReferences: true,\n\t\t\t\tid: 'ID',\n\t\t\t\tanchor: 'Anchor'\n\t\t\t} ]\n\t\t} ),\n\t\tsubsection = section.subsections[ 0 ];\n\n\tassert.strictEqual( section.subsections.length, 1, 'Subsection is added to array' );\n\tassert.ok( subsection instanceof Section, 'Subsections are instances of Section' );\n\n\tassert.strictEqual( subsection.line, 'Line', 'line is set' );\n\tassert.strictEqual( subsection.text, 'Text', 'text is set' );\n\tassert.strictEqual( subsection.hasReferences, true, 'hasReferences is set' );\n\tassert.strictEqual( subsection.id, 'ID', 'id is set' );\n\tassert.strictEqual( subsection.anchor, 'Anchor', 'anchor is set' );\n\tassert.strictEqual( subsection.subsections.length, 0, 'Subsection children are empty' );\n} );\n","/* eslint-env es6 */\n/* global $ */\nvar\n\tsinon = require( 'sinon' ),\n\tdom = require( '../utils/dom' ),\n\tjQuery = require( '../utils/jQuery' ),\n\too = require( '../utils/oo' ),\n\tmediawiki = require( '../utils/mw' ),\n\tsandbox,\n\tbrowser,\n\tToggler,\n\tsectionTemplate = `\n\t\t<h2>\n\t\t<span id=\"First_Section\">First Section</span>\n\t\t</h2>\n\t\t<div>\n\t\t\t<p>Text</p>\n\t\t</div>\n\t\t<h2 id=\"section_1\">\n\t\t\t<a href=\"#foo\">Dummy Link</a>\n\t\t</h2>\n\t\t<div></div>\n\t\t<h2>References</h2>\n\t\t<div data-is-reference-section=\"1\">\n\t\t\t<ol class=\"references\">\n\t\t\t\t<li id=\"cite_note-1\">\n\t\t\t\t\t<span class=\"mw-cite-backlink\">\n\t\t\t\t\t\t<a href=\"#cite_ref-1\">↑</a>\n\t\t\t\t\t</span> <span class=\"reference-text\">hello</span>\n\t\t\t\t</li>\n\t\t\t</ol>\n\t\t</div>\n`;\n\n/**\n * Mobile toggling\n */\nQUnit.module( 'MobileFrontend Toggler.js', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\too.setUp( sandbox, global );\n\t\tmediawiki.setUp( sandbox, global );\n\n\t\tbrowser = require( '../../../src/mobile.startup/Browser' ).getSingleton();\n\t\tToggler = require( '../../../src/mobile.startup/Toggler' );\n\n\t\tsandbox.stub( mw.config, 'get' ).withArgs( 'wgMFCollapseSectionsByDefault' ).returns( true );\n\t\tsandbox.stub( browser, 'isWideScreen' ).returns( false );\n\n\t\tthis.page = { title: 'Toggle test' };\n\t\tthis.$container = $( '<div>' ).html( sectionTemplate );\n\t\tthis.$section0 = this.$container.find( 'h2' ).eq( 0 );\n\t\tthis.title = this.page.title;\n\t\tthis.headline = this.$section0.find( 'span' ).attr( 'id' );\n\t},\n\tafterEach: function () {\n\t\tmw.storage.remove( 'expandSections' );\n\t\tmw.storage.remove( 'expandedSections' );\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( 'Mobile mode - Toggle section', function ( assert ) {\n\tvar\n\t\ttoggle = new Toggler( {\n\t\t\teventBus: new OO.EventEmitter(),\n\t\t\t$container: this.$container,\n\t\t\tprefix: '',\n\t\t\tpage: this.page\n\t\t} ),\n\t\t$section = this.$section0,\n\t\t$content = this.$container.find( '.collapsible-block' ).eq( 0 );\n\n\ttoggle.toggle( $section );\n\n\tassert.strictEqual( $section.hasClass( 'open-block' ), true, 'open-block class present' );\n\n\ttoggle.toggle( $section );\n\n\tassert.strictEqual( $content.hasClass( 'open-block' ), false, 'check content gets closed on a toggle' );\n\tassert.strictEqual( $section.hasClass( 'open-block' ), false, 'check section is closed' );\n\t// Perform second toggle\n\ttoggle.toggle( $section );\n\tassert.strictEqual( $content.hasClass( 'open-block' ), true, 'check content reopened' );\n\tassert.strictEqual( $section.hasClass( 'open-block' ), true, 'check section has reopened' );\n} );\n\nQUnit.test( 'Mobile mode - Clicking a hash link to reveal an already open section', function ( assert ) {\n\tvar\n\t\ttoggle = new Toggler( {\n\t\t\teventBus: new OO.EventEmitter(),\n\t\t\t$container: this.$container,\n\t\t\tprefix: '',\n\t\t\tpage: this.page\n\t\t} );\n\n\ttoggle.toggle( this.$section0 );\n\n\tassert.strictEqual( this.$section0.hasClass( 'open-block' ), true, 'check section is open' );\n\ttoggle.reveal( 'First_Section', this.$container );\n\tassert.strictEqual( this.$section0.hasClass( 'open-block' ), true, 'check section is still open' );\n} );\n\nQUnit.test( 'Mobile mode - Reveal element', function ( assert ) {\n\tvar\n\t\ttoggle = new Toggler( {\n\t\t\teventBus: new OO.EventEmitter(),\n\t\t\t$container: this.$container,\n\t\t\tprefix: '',\n\t\t\tpage: this.page\n\t\t} );\n\n\ttoggle.toggle( this.$section0 );\n\n\ttoggle.reveal( 'First_Section' );\n\tassert.strictEqual( this.$container.find( '.collapsible-block' ).eq( 0 ).hasClass( 'open-block' ), true, 'check content is visible' );\n\tassert.strictEqual( this.$section0.hasClass( 'open-block' ), true, 'check section is open' );\n} );\n\nQUnit.test( 'Mobile mode - Clicking hash links', function ( assert ) {\n\tvar\n\t\ttoggle = new Toggler( {\n\t\t\teventBus: new OO.EventEmitter(),\n\t\t\t$container: this.$container,\n\t\t\tprefix: '',\n\t\t\tpage: this.page\n\t\t} );\n\n\ttoggle.toggle( this.$section0 );\n\n\tthis.$container.find( '[href=\"#First_Section\"]' ).trigger( 'click' );\n\tassert.strictEqual( this.$container.find( '.collapsible-block' ).eq( 0 ).hasClass( 'open-block' ), true, 'check content is visible' );\n\tassert.strictEqual( this.$section0.hasClass( 'open-block' ), true, 'check section is open' );\n} );\n\nQUnit.test( 'Mobile mode - Tap event toggles section', function ( assert ) {\n\tvar\n\t\ttoggle = new Toggler( {\n\t\t\teventBus: new OO.EventEmitter(),\n\t\t\t$container: this.$container,\n\t\t\tprefix: '',\n\t\t\tpage: this.page\n\t\t} ),\n\t\t$content = this.$container.find( '.collapsible-block' ).eq( 1 );\n\n\ttoggle.toggle( this.$section0 );\n\n\tassert.strictEqual( $content.hasClass( 'open-block' ), false, 'check content is hidden at start' );\n\n\tthis.$container.find( '#section_1' ).trigger( 'click' );\n\n\tassert.strictEqual( $content.hasClass( 'open-block' ), true, 'check content is shown on a toggle' );\n} );\n\nQUnit.test( 'Accessibility - Verify aria attributes', function ( assert ) {\n\tvar\n\t\ttoggle = new Toggler( {\n\t\t\teventBus: new OO.EventEmitter(),\n\t\t\t$container: this.$container,\n\t\t\tprefix: '',\n\t\t\tpage: this.page\n\t\t} ),\n\t\t$section = this.$container.find( '#section_1' ),\n\t\t$content = this.$container.find( '.collapsible-block' ).eq( 1 );\n\n\ttoggle.toggle( this.$section0 );\n\n\t// Test the initial state produced by the init function\n\tassert.strictEqual( $content.hasClass( 'open-block' ), false, 'check content is hidden at start' );\n\tassert.strictEqual( $content.attr( 'aria-pressed' ), 'false', 'check aria-pressed is false at start' );\n\tassert.strictEqual( $content.attr( 'aria-expanded' ), 'false', 'check aria-expanded is false at start' );\n\n\t// Test what the toggle() function gives us when hiding the section\n\t$section.trigger( 'click' );\n\tassert.strictEqual( $content.hasClass( 'open-block' ), true, 'check content is visible after toggling' );\n\tassert.strictEqual( $content.attr( 'aria-pressed' ), 'true', 'check aria-pressed is true after toggling' );\n\tassert.strictEqual( $content.attr( 'aria-expanded' ), 'true', 'check aria-expanded is true after toggling' );\n\n\t// Test what the toggle() function gives us when showing the section\n\t$section.trigger( 'click' );\n\tassert.strictEqual( $content.hasClass( 'open-block' ), false, 'check content is hidden after toggling' );\n\tassert.strictEqual( $content.attr( 'aria-pressed' ), 'false', 'check aria-pressed is false after toggling' );\n\tassert.strictEqual( $content.attr( 'aria-expanded' ), 'false', 'check aria-expanded is false after toggling' );\n} );\n\n/**\n * Tablet toggling\n */\nQUnit.test( 'Tablet mode - Open by default', function ( assert ) {\n\tbrowser.isWideScreen.returns( true );\n\n\t/* eslint-disable-next-line no-new */\n\tnew Toggler( {\n\t\teventBus: new OO.EventEmitter(),\n\t\t$container: this.$container,\n\t\tprefix: '',\n\t\tpage: this.page\n\t} );\n\n\tassert.strictEqual( this.$container.find( '.collapsible-block' ).eq( 1 ).hasClass( 'open-block' ),\n\t\ttrue, 'check section is visible at start' );\n\tassert.strictEqual( this.$container.find( '.collapsible-block' ).eq( 2 ).hasClass( 'open-block' ),\n\t\tfalse, 'check reference section is hidden at start' );\n} );\n\n/**\n * Expand sections user setting\n */\nQUnit.test( 'Tablet mode - Open by default 2', function ( assert ) {\n\n\tmw.config.get.withArgs( 'wgMFCollapseSectionsByDefault' ).returns( false );\n\n\t/* eslint-disable-next-line no-new */\n\tnew Toggler( {\n\t\teventBus: new OO.EventEmitter(),\n\t\t$container: this.$container,\n\t\tprefix: '',\n\t\tpage: this.page\n\t} );\n\n\tassert.strictEqual( this.$container.find( '.collapsible-block' ).eq( 1 ).hasClass( 'open-block' ), true, 'check section is visible at start' );\n} );\n\n/**\n * Accessibility\n */\nQUnit.test( 'Accessibility - Pressing space/ enter toggles a heading', function ( assert ) {\n\tvar $section = this.$container.find( '#section_1' ),\n\t\t$content,\n\t\tev = $.Event( 'keypress' );\n\n\tbrowser.isWideScreen.returns( false );\n\tmw.config.get.withArgs( 'wgMFCollapseSectionsByDefault' ).returns( true );\n\n\t/* eslint-disable-next-line no-new */\n\tnew Toggler( {\n\t\teventBus: new OO.EventEmitter(),\n\t\t$container: this.$container,\n\t\tprefix: '',\n\t\tpage: this.page\n\t} );\n\n\t$content = this.$container.find( '.collapsible-block' ).eq( 1 );\n\n\tassert.strictEqual( $content.hasClass( 'open-block' ), false, 'check content is hidden at start' );\n\n\t// Open the section with pressing space\n\tev.which = 32;\n\t$section.trigger( ev );\n\tassert.strictEqual( $content.hasClass( 'open-block' ), true, 'check content is shown after pressing space' );\n\n\t// Enter should close the section again\n\tev.which = 13;\n\t$section.trigger( ev );\n\tassert.strictEqual( $content.hasClass( 'open-block' ), false, 'check content is hidden after pressing enter' );\n} );\n\nQUnit.test( 'Clicking a link within a heading isn\\'t triggering a toggle', function ( assert ) {\n\n\tvar $section = $( '#section_1' ),\n\t\t$content = $( '.collapsible-block' ).eq( 1 );\n\n\t/* eslint-disable-next-line no-new */\n\tnew Toggler( {\n\t\teventBus: new OO.EventEmitter(),\n\t\t$container: this.$container,\n\t\tprefix: '',\n\t\tpage: this.page\n\t} );\n\n\tassert.strictEqual( $content.hasClass( 'open-block' ), false, 'check content is hidden at start' );\n\n\t$section.find( '> a' ).eq( 0 ).trigger( 'mouseup' );\n\tassert.strictEqual( $content.hasClass( 'open-block' ), false, 'check content is still being hidden after clicking on the link' );\n} );\n\nQUnit.test( 'Toggling a section stores its state.', function ( assert ) {\n\n\tvar\n\t\ttoggle = new Toggler( {\n\t\t\teventBus: new OO.EventEmitter(),\n\t\t\t$container: this.$container,\n\t\t\tprefix: '',\n\t\t\tpage: this.page\n\t\t} ),\n\t\t$section = this.$container.find( 'h2' ),\n\t\texpandedSections = Toggler._getExpandedSections( this.page ),\n\t\tmwStorageSetSpy = sandbox.spy( mw.storage, 'set' ),\n\t\tmwStorageSetCall,\n\t\tmwStorageSetCall2;\n\n\tassert.strictEqual( $.isEmptyObject( expandedSections[ this.title ] ),\n\t\ttrue,\n\t\t'no user setting about an expanded section exists already'\n\t);\n\n\ttoggle.toggle( $section );\n\tmwStorageSetCall = JSON.parse( mwStorageSetSpy.getCall( 0 ).args[1] );\n\n\tassert.strictEqual( typeof mwStorageSetCall[ this.title ][ this.headline ],\n\t\t'number',\n\t\t'the just toggled section state has been saved'\n\t);\n\n\ttoggle.toggle( $section );\n\tmwStorageSetCall2 = JSON.parse( mwStorageSetSpy.getCall( 1 ).args[1] );\n\n\tassert.strictEqual( mwStorageSetCall2[ this.title ][ this.headline ],\n\t\tundefined,\n\t\t'the just toggled section state has been removed'\n\t);\n\n} );\n\nQUnit.test( 'Check for and remove obsolete stored sections.', function ( assert ) {\n\tvar\n\t\texpandedSections,\n\t\tmwStorageSetSpy,\n\t\tlocalStorageValue,\n\t\tlocalStorageRemovalValue;\n\n\tlocalStorageValue = {};\n\tlocalStorageValue[ this.title ] = {};\n\tlocalStorageValue[ this.title ][ this.headline ] = ( new Date( 1990, 1, 1 ) ).getTime();\n\n\tsandbox.stub( mw.storage, 'get', function () {\n\t\treturn JSON.stringify( localStorageValue );\n\t} );\n\n\texpandedSections = Toggler._getExpandedSections( this.page );\n\tassert.strictEqual( typeof expandedSections[ this.title ][ this.headline ],\n\t\t'number',\n\t\t'manually created section state has been saved correctly'\n\t);\n\n\tmwStorageSetSpy = sandbox.spy( mw.storage, 'set' );\n\n\tToggler._cleanObsoleteStoredSections( this.page );\n\tlocalStorageRemovalValue = JSON.stringify( [ 'expandedSections', '{\"Toggle test\":{}}' ] );\n\tassert.strictEqual(\n\t\tJSON.stringify( mwStorageSetSpy.getCall( 0 ).args ),\n\t\tlocalStorageRemovalValue,\n\t\t'section, whose store time is manually changed to an older date,' +\n\t\t\t'has been removed from storage correctly'\n\t);\n} );\n\nQUnit.test( 'Expanding already expanded section does not toggle it.', function ( assert ) {\n\tvar\n\t\ttoggle = new Toggler( {\n\t\t\teventBus: new OO.EventEmitter(),\n\t\t\t$container: this.$container,\n\t\t\tprefix: '',\n\t\t\tpage: this.page\n\t\t} ),\n\t\t$section = this.$container.find( 'h2' ),\n\t\texpandedSections = Toggler._getExpandedSections( this.page ),\n\t\tmwStorageSetSpy,\n\t\tmwStorageSetCall;\n\n\tassert.strictEqual( $.isEmptyObject( expandedSections[ this.title ] ),\n\t\ttrue,\n\t\t'no expanded sections are stored in localStorage yet'\n\t);\n\n\tassert.strictEqual(\n\t\t$section.hasClass( 'open-block' ),\n\t\tfalse,\n\t\t'section does not have open-block class'\n\t);\n\n\tmwStorageSetSpy = sandbox.spy( mw.storage, 'set' );\n\n\t// manually toggle the second section\n\ttoggle.toggle( $section );\n\n\tassert.strictEqual(\n\t\t$section.hasClass( 'open-block' ),\n\t\ttrue,\n\t\t'revealed section has open-block class'\n\t);\n\n\texpandedSections = Toggler._getExpandedSections( this.page );\n\tmwStorageSetCall = JSON.parse( mwStorageSetSpy.getCall( 0 ).args[1] );\n\n\tassert.strictEqual( typeof mwStorageSetCall[this.title][ this.headline ],\n\t\t'number',\n\t\t'manually revealed section state has been correctly saved in localStorage'\n\t);\n\n\tToggler._expandStoredSections( toggle, this.$container, this.page );\n\n\tassert.strictEqual(\n\t\t$section.hasClass( 'open-block' ),\n\t\ttrue,\n\t\t'already revealed section still has open-block class after expanding sections'\n\t);\n} );\n\nQUnit.test( 'MobileFrontend toggle.js - Expand stored sections.', function ( assert ) {\n\n\tvar\n\t\t$section = this.$container.find( 'h2' ).eq( 0 ),\n\t\texpandedSections = Toggler._getExpandedSections( this.page ),\n\t\texpandedSectionsFromToggle;\n\n\t// Restore expanded sections only works on headings that are also section headings\n\tthis.$container.find( 'h2' ).addClass( 'section-heading' );\n\n\tassert.strictEqual( $section.hasClass( 'open-block' ), false, 'Section is collapsed.' );\n\n\tassert.strictEqual( $.isEmptyObject( expandedSections[ this.title ] ),\n\t\ttrue,\n\t\t'no user setting about an expanded section exists already'\n\t);\n\n\t// save a toggle state manually\n\texpandedSections[ this.title ][ this.headline ] = ( new Date() ).getTime();\n\n\tsandbox.stub( mw.storage, 'get', function () {\n\t\treturn JSON.stringify( expandedSections );\n\t} );\n\texpandedSectionsFromToggle = Toggler._getExpandedSections( this.page );\n\tassert.strictEqual( typeof expandedSectionsFromToggle[ this.title ][ this.headline ],\n\t\t'number',\n\t\t'manually created section state has been saved correctly'\n\t);\n\n\t/* eslint-disable-next-line no-new */\n\tnew Toggler( {\n\t\teventBus: new OO.EventEmitter(),\n\t\t$container: this.$container,\n\t\tprefix: '',\n\t\tpage: this.page\n\t} );\n\n\texpandedSections = Toggler._getExpandedSections( this.page );\n\tassert.strictEqual( typeof expandedSections[ this.title ][ this.headline ],\n\t\t'number',\n\t\t'manually created section state is still active after toggle.init()'\n\t);\n\tassert.strictEqual( $section.hasClass( 'open-block' ), true,\n\t\t'Saved section has been auto expanded.' );\n\n} );\n","/* global $ */\nvar\n\tHogan = require( 'hogan.js' ),\n\tmw = require( '../utils/mw' ),\n\tjQuery = require( '../utils/jQuery' ),\n\tdom = require( '../utils/dom' ),\n\tmfExtend = require( '../../../src/mobile.startup/mfExtend' ),\n\tutil = require( '../../../src/mobile.startup/util' ),\n\too = require( '../utils/oo' ),\n\tsinon = require( 'sinon' ),\n\tView;\n/** @type {sinon.SinonSandbox} */ var sandbox; // eslint-disable-line one-var\n\nQUnit.module( 'MobileFrontend mobile.startup/View', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\too.setUp( sandbox, global );\n\t\tmw.setUp( sandbox, global );\n\n\t\tView = require( '../../../src/mobile.startup/View' );\n\t},\n\tafterEach: function () {\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( 'View', function ( assert ) {\n\tvar view = new View( {\n\t\tel: 'body'\n\t} );\n\tassert.ok( view.$el instanceof $, 'assign jQuery object to $el' );\n\tassert.strictEqual( view.$el[ 0 ].tagName.toUpperCase(), 'BODY', 'assign proper jQuery object to $el' );\n} );\n\nQUnit.test( 'View, jQuery proxy functions', function ( assert ) {\n\tvar view = new View( {\n\t\tel: 'body'\n\t} );\n\t[\n\t\t'append',\n\t\t'prepend',\n\t\t'appendTo',\n\t\t'prependTo',\n\t\t'after',\n\t\t'before',\n\t\t'insertAfter',\n\t\t'insertBefore',\n\t\t'remove',\n\t\t'detach'\n\t].forEach( function ( prop ) {\n\t\tvar stub = sandbox.stub( view.$el, prop );\n\t\tview[ prop ]( 'test', 1 );\n\t\tassert.ok( stub.calledWith( 'test', 1 ) );\n\t\tstub.restore();\n\t} );\n} );\n\nQUnit.test( 'View#preRender', function ( assert ) {\n\tvar view;\n\tfunction ChildView() {\n\t\tView.apply( this, arguments );\n\t}\n\n\tmfExtend( ChildView, View, {\n\t\ttemplate: Hogan.compile( '<p>{{text}}</p>' ),\n\t\tpreRender: function () {\n\t\t\tthis.options.text = 'hello';\n\t\t}\n\t} );\n\n\tview = new ChildView();\n\tassert.strictEqual( view.$el.html(), '<p>hello</p>', 'manipulate template data' );\n} );\n\nQUnit.test( 'View#postRender', function ( assert ) {\n\tvar spy = sandbox.spy();\n\tfunction ChildView() {\n\t\tView.apply( this, arguments );\n\t}\n\n\tmfExtend( ChildView, View, {\n\t\tpostRender: function () {\n\t\t\tspy();\n\t\t}\n\t} );\n\n\t// eslint-disable-next-line no-new\n\tnew ChildView();\n\tassert.strictEqual( spy.callCount, 1, 'invoke postRender' );\n} );\n\nQUnit.test( 'View#delegateEvents', function ( assert ) {\n\n\tvar view;\n\tfunction EventsView( props ) {\n\t\tView.call(\n\t\t\tthis,\n\t\t\tutil.extend(\n\t\t\t\t{\n\t\t\t\t\tevents: {\n\t\t\t\t\t\t'click p span': function ( ev ) {\n\t\t\t\t\t\t\tev.preventDefault();\n\t\t\t\t\t\t\tassert.ok( true, 'Span was clicked and handled' );\n\t\t\t\t\t\t},\n\t\t\t\t\t\t'click p': 'onParagraphClick',\n\t\t\t\t\t\tclick: 'onClick'\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tprops\n\t\t\t)\n\t\t);\n\t}\n\n\tmfExtend( EventsView, View, {\n\t\ttemplate: Hogan.compile( '<p><span>test</span></p>' ),\n\t\tonParagraphClick: function ( ev ) {\n\t\t\tev.preventDefault();\n\t\t\tassert.ok( true, 'Paragraph was clicked and handled' );\n\t\t},\n\t\tonClick: function ( ev ) {\n\t\t\tev.preventDefault();\n\t\t\tassert.ok( true, 'View was clicked and handled' );\n\t\t}\n\t} );\n\n\tview = new EventsView();\n\tview.appendTo( 'body' );\n\t// Check if events are set and handlers called\n\tview.$el.find( 'span' ).trigger( 'click' );\n\tview.$el.find( 'p' ).trigger( 'click' );\n\tview.$el.trigger( 'click' );\n\t// Check if events can be unset and handlers are not called\n\tview.undelegateEvents();\n\tview.$el.find( 'span' ).trigger( 'click' );\n\tview.$el.find( 'p' ).trigger( 'click' );\n\tview.$el.trigger( 'click' );\n} );\n\nQUnit.test( 'View#render (with isTemplateMode)', function ( assert ) {\n\tvar view, view2, textFirstRun,\n\t\t$parent = $( '<div>' );\n\tfunction TemplateModeView() {\n\t\tView.apply( this, arguments );\n\t}\n\n\tmfExtend( TemplateModeView, View, {\n\t\ttemplate: Hogan.compile( '<p class=\"foo\"><span>{{text}}</span></p>' ),\n\t\tisTemplateMode: true\n\t} );\n\n\tfunction ContainerView() {\n\t\tView.call( this, { className: 'bar' } );\n\t}\n\n\tmfExtend( ContainerView, View, {\n\t\ttemplate: Hogan.compile( '<p class=\"foo\"><span>test</span></p>' )\n\t} );\n\n\tview = new TemplateModeView();\n\ttextFirstRun = view.$el.text();\n\tview2 = new ContainerView();\n\tview.render();\n\tview2.render();\n\t// attach to the DOM\n\tview.$el.appendTo( $parent );\n\t// and then do a second render...\n\tview.render( { text: 'hello' } );\n\tassert.ok( view.$el.hasClass( 'foo' ) );\n\tassert.ok( view2.$el.hasClass( 'bar' ) );\n\tassert.strictEqual( textFirstRun, '', 'first run, no text defined' );\n\tassert.strictEqual( view.$el.text(), 'hello', 'second run, text has been defined' );\n\tassert.strictEqual( view.$el.parent( $parent ).length, 1,\n\t\t'A re-rendered view thats attached to the DOM remains attached to the DOM' );\n} );\n\nQUnit.test( 'View#render events (with isTemplateMode)', function ( assert ) {\n\tvar view;\n\tfunction TemplateModeView( props ) {\n\t\tView.call(\n\t\t\tthis,\n\t\t\tutil.extend( { events: { 'click span': 'onClick' } }, props )\n\t\t);\n\t}\n\n\tmfExtend( TemplateModeView, View, {\n\t\tonClick: function () {\n\t\t\tthis.$el.empty().text( 'hello world' );\n\t\t},\n\t\ttemplate: Hogan.compile( '<p class=\"foo\"><span>test</span></p>' ),\n\t\tisTemplateMode: true\n\t} );\n\n\tview = new TemplateModeView();\n\t// trigger event\n\tview.$el.find( 'span' ).trigger( 'click' );\n\tassert.strictEqual( view.$el.text(), 'hello world', 'event was called' );\n\tassert.strictEqual( view.$el.find( 'span' ).length, 0, 'span disappeared' );\n\n\t// do same again but call render twice\n\tview = new TemplateModeView();\n\t// force a re-render\n\tview.render();\n\t// trigger event to show events didn't get lost\n\tview.$el.find( 'span' ).trigger( 'click' );\n\tassert.strictEqual( view.$el.text(), 'hello world', 'event was called' );\n\tassert.strictEqual( view.$el.find( 'span' ).length, 0, 'span disappeared' );\n} );\n\nQUnit.test( 'View with className option', function ( assert ) {\n\t[\n\t\t[\n\t\t\tnew View(),\n\t\t\t'view-border-box',\n\t\t\t'className not defined on a normal View without options and isBorderBox is default'\n\t\t],\n\t\t[\n\t\t\tnew View( {} ),\n\t\t\t'view-border-box',\n\t\t\t'className not defined on a normal View with empty options and isBorderBox is default'\n\t\t],\n\t\t[\n\t\t\tnew View( {\n\t\t\t\tclassName: 'banana'\n\t\t\t} ),\n\t\t\t'banana view-border-box',\n\t\t\t'option is passed to View (along with default isBorderBox property)'\n\t\t],\n\t\t[\n\t\t\tnew View( { isBorderBox: false } ),\n\t\t\tundefined,\n\t\t\t'Passing isBorderBox option removes default view-border-box class'\n\t\t],\n\t\t[\n\t\t\tnew View( { isBorderBox: true } ),\n\t\t\t'view-border-box',\n\t\t\t'Passing isBorderBox option as true retains default view-border-box class'\n\t\t]\n\t].forEach( function ( test ) {\n\t\tassert.strictEqual( test[0].$el.attr( 'class' ), test[1], test[2] );\n\t} );\n} );\n\nQUnit.test( 'View.make()', function ( assert ) {\n\tvar view = View.make( { className: 'foo' }, [ util.parseHTML( '<div>' ).text( 'hello' ) ] );\n\tassert.strictEqual( view.$el.find( '> div' ).text().trim(), 'hello', 'view created with element' );\n} );\n","var cache = require( '../../../src/mobile.startup/cache' ),\n\tMemoryCache = cache.MemoryCache,\n\tmemoryCache = new MemoryCache();\n\nQUnit.module( 'MobileFrontend cache.js' );\n\nQUnit.test( 'cache set() and get()', function ( assert ) {\n\tmemoryCache.set( 'key', 'value' );\n\tassert.strictEqual( memoryCache.get( 'key' ), 'value' );\n} );\n","var sandbox,\n\tsinon = require( 'sinon' ),\n\tmediaWiki = require( '../utils/mw' ),\n\tcontext = require( '../../../src/mobile.startup/context' );\n\nQUnit.module( 'MobileFrontend context.js', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t\tmediaWiki.setUp( sandbox, global );\n\t},\n\tafterEach: function () { sandbox.restore(); }\n} );\n\nQUnit.test( 'getMode()', function ( assert ) {\n\tsandbox.stub( mw.config, 'get' ).withArgs( 'wgMFMode' )\n\t\t.returns( 'stable' );\n\tassert.strictEqual( context.getMode(), 'stable', 'Value comes straight from config' );\n} );\n","var sandbox, extendSearchParams,\n\tjQuery = require( '../utils/jQuery' ),\n\tmediaWiki = require( '../utils/mw' ),\n\tdom = require( '../utils/dom' ),\n\tsinon = require( 'sinon' );\n\nQUnit.module( 'MobileFrontend extendSearchParams.js', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t\tmediaWiki.setUp( sandbox, global );\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\tsandbox.stub( mw.config, 'get' )\n\t\t\t.withArgs( 'wgMFSearchAPIParams' ).returns(\n\t\t\t\t{\n\t\t\t\t\tfoo: 'bar'\n\t\t\t\t}\n\t\t\t)\n\t\t\t.withArgs( 'wgMFDisplayWikibaseDescriptions' ).returns(\n\t\t\t\t{\n\t\t\t\t\tsearch: true,\n\t\t\t\t\tnearby: false\n\t\t\t\t}\n\t\t\t)\n\t\t\t.withArgs( 'wgMFQueryPropModules' ).returns( [ 'baz' ] );\n\t\textendSearchParams = require( '../../../src/mobile.startup/extendSearchParams' );\n\t},\n\tafterEach: function () {\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( 'it throws if the feature is invalid', function ( assert ) {\n\tvar expectedError = new Error( '\"foo\" isn\\'t a feature that shows Wikibase descriptions.' );\n\n\tassert.throws( function () {\n\t\textendSearchParams( 'foo', {} );\n\t}, expectedError );\n} );\n\nQUnit.test( 'it extends the parameters', function ( assert ) {\n\tvar params = extendSearchParams( 'search', {\n\t\t\tqux: 'quux',\n\t\t\tprop: [ 'corge' ]\n\t\t} ),\n\t\texpectedParams = {\n\t\t\taction: 'query',\n\t\t\tformatversion: 2,\n\t\t\tqux: 'quux',\n\t\t\tfoo: 'bar', // from wgMFSearchAPIParams\n\t\t\tprop: [ 'corge', 'baz', 'description' ] // from wgMFQueryPropModules and Wikibase-specific\n\t\t};\n\n\tassert.propEqual( params, expectedParams );\n} );\n\nQUnit.test( 'it doesn\\'t include Wikibase-specific parameters if the feature is disabled', function ( assert ) {\n\tvar params = extendSearchParams( 'nearby', {\n\t\tqux: 'quux'\n\t} );\n\n\tassert.strictEqual( params.prop.indexOf( 'description' ), -1 );\n\tassert.strictEqual( params.wbptterms, undefined );\n} );\n\nQUnit.test( 'it adds the MobileFrontend configuration to given terms types', function ( assert ) {\n\tvar params = extendSearchParams( 'search', {\n\t\twbptterms: 'grault'\n\t} );\n\n\tassert.strictEqual(\n\t\tparams.wbptterms,\n\t\t'grault',\n\t\t'The given \"wbptterms\" is added to the default.'\n\t);\n} );\n\nQUnit.test( 'it prioritizes MobileFrontend configuration', function ( assert ) {\n\tvar params = extendSearchParams( 'search', {\n\t\t\tfoo: 'quux'\n\t\t} ),\n\t\texpectedParams = {\n\t\t\taction: 'query',\n\t\t\tformatversion: 2,\n\t\t\tfoo: 'bar',\n\t\t\tprop: [ 'baz', 'description' ]\n\t\t};\n\n\tassert.propEqual(\n\t\tparams,\n\t\texpectedParams,\n\t\t'The value of \"foo\" is overridden by the configuration.'\n\t);\n} );\n\nQUnit.test( 'it is variadic', function ( assert ) {\n\tvar params = extendSearchParams(\n\t\t\t'search',\n\t\t\t{\n\t\t\t\tbaz: 'qux'\n\t\t\t},\n\t\t\t{\n\t\t\t\tquux: 'corge'\n\t\t\t}\n\t\t),\n\t\texpectedParams = {\n\t\t\taction: 'query',\n\t\t\tformatversion: 2,\n\t\t\tfoo: 'bar',\n\t\t\tbaz: 'qux',\n\t\t\tquux: 'corge',\n\t\t\tprop: [ 'baz', 'description' ]\n\t\t};\n\n\tassert.propEqual( params, expectedParams );\n} );\n","var sandbox, icons, spy,\n\tsinon = require( 'sinon' ),\n\tdom = require( '../utils/dom' ),\n\tjQuery = require( '../utils/jQuery' ),\n\tmediaWiki = require( '../utils/mw' ),\n\too = require( '../utils/oo' );\n\nQUnit.module( 'MobileFrontend icons.js', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\too.setUp( sandbox, global );\n\t\tmediaWiki.setUp( sandbox, global );\n\t\ticons = require( '../../../src/mobile.startup/icons' );\n\t\tspy = sandbox.spy( icons, 'Icon' );\n\t},\n\tafterEach: function () {\n\t\tsandbox.restore();\n\t\tjQuery.tearDown();\n\t}\n} );\n\nQUnit.test( '#cancel()', function ( assert ) {\n\ticons.cancel();\n\tassert.propEqual( spy.getCall( 0 ).args[ 0 ], {\n\t\ttagName: 'button',\n\t\tname: icons.CANCEL_GLYPH,\n\t\tadditionalClassNames: 'cancel',\n\t\tlabel: mw.msg( 'mobile-frontend-overlay-close' )\n\t}, 'Options are passed down' );\n} );\n\nQUnit.test( '#cancel(variant)', function ( assert ) {\n\ticons.cancel( 'gray' );\n\tassert.propEqual( spy.getCall( 0 ).args[ 0 ], {\n\t\ttagName: 'button',\n\t\tname: icons.CANCEL_GLYPH + '-gray',\n\t\tadditionalClassNames: 'cancel',\n\t\tlabel: mw.msg( 'mobile-frontend-overlay-close' )\n\t}, 'Options are passed down' );\n} );\n\nQUnit.test( '#spinner()', function ( assert ) {\n\ticons.spinner( {\n\t\tfoo: 'will be passed down',\n\t\tadditionalClassNames: 'will-be-ignored'\n\t} );\n\tassert.propEqual( spy.getCall( 0 ).args[ 0 ], {\n\t\tfoo: 'will be passed down',\n\t\tadditionalClassNames: 'spinner loading',\n\t\tname: 'spinner',\n\t\tlabel: mw.msg( 'mobile-frontend-loading-message' )\n\t}, 'Options are passed down' );\n} );\n","let\n\tsandbox,\n\tgetDeviceLanguage = require( '../../../../src/mobile.startup/languageOverlay/getDeviceLanguage' ),\n\tsinon = require( 'sinon' );\n\nQUnit.module( 'MobileFrontend getDeviceLanguage', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t},\n\tafterEach: function () {\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( 'returns language code of device in lowercase', function ( assert ) {\n\tconst cases = [\n\t\t[ {}, undefined ],\n\t\t[ { languages: [ 'en-US' ] }, 'en-us' ],\n\t\t[ { language: 'en-US' }, 'en-us' ],\n\t\t[ { userLanguage: 'en-US' }, 'en-us' ],\n\t\t[ { browserLanguage: 'en-US' }, 'en-us' ],\n\t\t[ { systemLanguage: 'en-US' }, 'en-us' ]\n\t];\n\n\tcases.forEach( function ( testCase ) {\n\t\tconst result = getDeviceLanguage( testCase[ 0 ] );\n\t\tassert.strictEqual( result, testCase[1], 'returns correct code' );\n\t} );\n} );\n","let\n\tlanguageOverlay,\n\tLanguageSearcher,\n\tsandbox,\n\theadless = typeof window !== 'object',\n\tm = require( '../../../../src/mobile.startup/moduleLoaderSingleton' ),\n\tutil = require( '../../../../src/mobile.startup/util' ),\n\tjQuery = require( '../../utils/jQuery' ),\n\tdom = require( '../../utils/dom' ),\n\too = require( '../../utils/oo' ),\n\tmediaWiki = require( '../../utils/mw' ),\n\tsinon = require( 'sinon' );\n\nQUnit.module( 'MobileFrontend languageOverlay.js', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\too.setUp( sandbox, global );\n\t\tmediaWiki.setUp( sandbox, global );\n\n\t\tLanguageSearcher = require( '../../../../src/mobile.languages.structured/LanguageSearcher' );\n\t\tlanguageOverlay = require( '../../../../src/mobile.startup/languageOverlay/languageOverlay' );\n\n\t\tsandbox.stub( mw, 'msg' )\n\t\t\t.withArgs( 'mobile-frontend-language-heading' ).returns( '' )\n\t\t\t.withArgs( 'mobile-frontend-loading-message' ).returns( '⌛' )\n\t\t\t.withArgs( 'mobile-frontend-languages-structured-overlay-all-languages-header' ).returns( '' )\n\t\t\t.withArgs( 'mobile-frontend-languages-structured-overlay-suggested-languages-header' ).returns( '' );\n\t\tsandbox.stub( mw.loader, 'using' ).withArgs( 'mobile.languages.structured' ).returns( util.Deferred().resolve() );\n\n\t\t// languageOverlay uses a global navigator so we need to stub it for headless tests\n\t\tif ( headless ) {\n\t\t\tglobal.navigator = global.navigator || undefined;\n\t\t\tsandbox.stub( global, 'navigator', {} );\n\t\t}\n\n\t\tsandbox.stub( m, 'require' ).withArgs( 'mobile.languages.structured/LanguageSearcher' ).returns( LanguageSearcher );\n\t},\n\tafterEach: function () {\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( '#constructor', function ( assert ) {\n\tconst\n\t\tgatewayDeferred = util.Deferred().resolve( {\n\t\t\tlanguages: [],\n\t\t\tvariants: []\n\t\t} ),\n\t\tgateway = {\n\t\t\tgetPageLanguages: function () {\n\t\t\t\treturn gatewayDeferred;\n\t\t\t}\n\t\t},\n\t\toverlay = languageOverlay( gateway );\n\n\tassert.strictEqual( overlay.$el.find( '.overlay-content > .promised-view' ).text(), '⌛', 'loading view rendered in .overlay-content' );\n\n\treturn languageOverlay.test.loadLanguageSearcher( gateway ).then( function () {\n\t\tassert.strictEqual( overlay.$el.find( '.overlay-content > .promised-view' ).length, 0, 'promisedView has fulfilled its promise' );\n\t\tassert.strictEqual( overlay.$el.find( '.overlay-content > .language-searcher' ).length, 1, 'loaded view rendered in .overlay-content' );\n\t} );\n} );\n","var\n\tjQuery = require( '../../utils/jQuery' ),\n\tdom = require( '../../utils/dom' ),\n\tlazyImageLoader = require( '../../../../src/mobile.startup/lazyImages/lazyImageLoader' ),\n\tmediaWiki = require( '../../utils/mw' ),\n\tsinon = require( 'sinon' ),\n\tsandbox;\n\nQUnit.module( 'MobileFrontend lazyImageLoader.js', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global ); // Needed for Deferreds.\n\t\tmediaWiki.setUp( sandbox, global ); // util.Deferred() uses mw.log().\n\t},\n\tafterEach: function () {\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n}, function () {\n\tQUnit.test( '#queryPlaceholders() empty', function ( assert ) {\n\t\tvar\n\t\t\troot = document.createElement( 'div' ),\n\t\t\tactual = lazyImageLoader.queryPlaceholders( root );\n\t\tassert.propEqual( actual, [], 'The result is empty.' );\n\t} );\n\n\tQUnit.test( '#queryPlaceholders() nonempty', function ( assert ) {\n\t\tvar\n\t\t\troot = document.createElement( 'div' ),\n\t\t\tplaceholder = document.createElement( 'div' ),\n\t\t\tactual;\n\t\tplaceholder.className = lazyImageLoader.test.placeholderClass;\n\t\troot.appendChild( placeholder );\n\n\t\tactual = lazyImageLoader.queryPlaceholders( root );\n\t\tassert.propEqual( actual, [ placeholder ], 'The result is nonempty.' );\n\t} );\n\n\tQUnit.test( '#loadImage() copy attributes', function ( assert ) {\n\t\tvar\n\t\t\tattrs = {\n\t\t\t\twidth: '1',\n\t\t\t\theight: '2',\n\t\t\t\tclass: 'class',\n\t\t\t\talt: 'alt',\n\t\t\t\tsrc: '/src',\n\t\t\t\tsrcset: '/srcset'\n\t\t\t},\n\t\t\tplaceholder = document.createElement( 'div' ),\n\t\t\tresult;\n\t\t// Placeholder className is not copied (class), style (not data-style) is.\n\t\tplaceholder.className = lazyImageLoader.test.placeholderClass;\n\t\tplaceholder.style.width = '3px';\n\t\tObject.keys( attrs ).forEach( function ( name ) {\n\t\t\tplaceholder.setAttribute( 'data-' + name, attrs[name] );\n\t\t} );\n\n\t\tresult = lazyImageLoader.loadImage( placeholder );\n\n\t\tObject.keys( attrs ).forEach( function ( name ) {\n\t\t\tassert.strictEqual( result.image.getAttribute( name ), attrs[name], name + ' is set.' );\n\t\t} );\n\t\tassert.strictEqual( result.image.style.width, '3px', 'Style from placeholder is set.' );\n\t} );\n\n\tQUnit.test( '#loadImage() loaded', function ( assert ) {\n\t\tvar\n\t\t\tplaceholder = document.createElement( 'div' ),\n\t\t\tresult;\n\n\t\tresult = lazyImageLoader.loadImage( placeholder );\n\t\tresult.image.dispatchEvent( new Event( 'load' ) );\n\t\treturn result.promise.then( function ( status ) {\n\t\t\tassert.strictEqual( status, 'load', 'Promise resolves on load.' );\n\t\t} );\n\t} );\n\n\tQUnit.test( '#loadImage() load error', function ( assert ) {\n\t\tvar\n\t\t\tplaceholder = document.createElement( 'div' ),\n\t\t\tresult;\n\n\t\tresult = lazyImageLoader.loadImage( placeholder );\n\t\tresult.image.dispatchEvent( new Event( 'error' ) );\n\t\treturn result.promise.then( function ( status ) {\n\t\t\tassert.strictEqual( status, 'error', 'Promise resolves even on error.' );\n\t\t} );\n\t} );\n\n\tQUnit.test( '#loadImages() empty', function ( assert ) {\n\t\treturn lazyImageLoader.loadImages( [] ).then( function () {\n\t\t\tassert.ok( true, 'Promise resolves.' );\n\t\t} );\n\t} );\n\n\tQUnit.test( '#loadImages() nonempty', function ( assert ) {\n\t\tvar\n\t\t\tplaceholder = document.createElement( 'div' ),\n\t\t\timage = new Image(),\n\t\t\tdeferred;\n\n\t\tsandbox.stub( global, 'Image' ).returns( image );\n\t\tdeferred = lazyImageLoader.loadImages( [ placeholder ] ).then( function () {\n\t\t\tassert.ok( true, 'Promise resolves.' );\n\t\t} );\n\t\timage.dispatchEvent( new Event( 'load' ) );\n\n\t\treturn deferred;\n\t} );\n\n\tQUnit.test( '#loadImages() plural', function ( assert ) {\n\t\tvar\n\t\t\tplaceholder = document.createElement( 'div' ),\n\t\t\timage = new Image(),\n\t\t\tdeferred;\n\n\t\tsandbox.stub( global, 'Image' ).returns( image );\n\t\tdeferred = lazyImageLoader.loadImages( [ placeholder, placeholder ] ).then(\n\t\t\tfunction () { assert.ok( true, 'Promise resolves.' ); }\n\t\t);\n\t\timage.dispatchEvent( new Event( 'load' ) );\n\n\t\treturn deferred;\n\t} );\n\n\tQUnit.test( '#loadImages() one fails to load, one succeeds', function ( assert ) {\n\t\tvar\n\t\t\tplaceholder = document.createElement( 'div' ),\n\t\t\tfailureImage = new Image(),\n\t\t\tsuccessImage = new Image(),\n\t\t\tdeferred;\n\n\t\tsandbox\n\t\t\t.stub( global, 'Image' )\n\t\t\t.onFirstCall().returns( failureImage )\n\t\t\t.onSecondCall().returns( successImage );\n\t\tdeferred = lazyImageLoader.loadImages( [ placeholder, placeholder ] ).then(\n\t\t\tfunction () { assert.ok( true, 'Promise resolves.' ); }\n\t\t);\n\t\tfailureImage.dispatchEvent( new Event( 'error' ) );\n\t\tsuccessImage.dispatchEvent( new Event( 'load' ) );\n\n\t\treturn deferred;\n\t} );\n\n} );\n","var\n\tpages = require( './../utils/PageInputs.html' ),\n\tjQuery = require( '../utils/jQuery' ),\n\tdom = require( '../utils/dom' ),\n\tmediaWiki = require( '../utils/mw' ),\n\too = require( '../utils/oo' ),\n\tlazyReferencesLoader,\n\tsinon = require( 'sinon' ),\n\tutil = require( '../../../src/mobile.startup/util' ),\n\tsandbox,\n\tPage;\n\nQUnit.module( 'MobileFrontend lazyReferencesLoader.js', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\too.setUp( sandbox, global );\n\t\tmediaWiki.setUp( sandbox, global );\n\n\t\tPage = require( '../../../src/mobile.startup/Page' );\n\t\tlazyReferencesLoader = require( '../../../src/mobile.startup/lazyReferencesLoader' );\n\t},\n\tafterEach: function () {\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( '#lazyReferencesLoader collapsed', function ( assert ) {\n\tvar\n\t\t$content = util.parseHTML( '<div>' ).append( pages.skinPage ),\n\t\teventBus = {\n\t\t\ton: function () {},\n\t\t\toff: function () {},\n\t\t\temit: function () {}\n\t\t},\n\t\tgateway = {\n\t\t\tgetReferencesLists: function () {},\n\t\t\tgetReferencesList: function () {}\n\t\t},\n\t\tpage = new Page( { title: 'Foo' } );\n\n\tsandbox.stub( gateway, 'getReferencesLists' ).returns( util.Deferred().resolve( {} ) );\n\tsandbox.stub( gateway, 'getReferencesList' )\n\t\t.withArgs( page, 'Notes_and_references' ).returns( util.Deferred().resolve( util.parseHTML( '<p>' ).text( 'P' ) ) )\n\t\t.withArgs( page, 'Notes' ).returns( util.Deferred().resolve( util.parseHTML( '<p>' ).text( 'A' ) ) )\n\t\t.withArgs( page, 'Refs' ).returns( util.Deferred().resolve( util.parseHTML( '<p>' ).text( 'B' ) ) )\n\t\t.withArgs( page, 'More_refs' ).returns( util.Deferred().resolve( util.parseHTML( '<p>' ).html( '<p>E</p><p>F</p>' ).children() ) );\n\n\treturn lazyReferencesLoader.loadReferences( eventBus, {\n\t\texpanded: false,\n\t\tpage: page,\n\t\tisReferenceSection: true,\n\t\t$heading: $content.find( '#Notes_and_references' ).parent()\n\t}, gateway, page ).then( function () {\n\t\tassert.strictEqual( $content.find( '.mf-section-2' ).text().replace( /[\\t\\n]/g, '' ),\n\t\t\t'TextPNotesARefsBno forgetMore refs1E2F3',\n\t\t\t'Check all the references section is populated correctly.' );\n\t} );\n} );\n\nQUnit.test( '#lazyReferencesLoader expanded', function ( assert ) {\n\tvar\n\t\t$content = util.parseHTML( '<div>' ).append( pages.skinPage ),\n\t\teventBus = {\n\t\t\ton: function () {},\n\t\t\toff: function () {},\n\t\t\temit: function () {}\n\t\t},\n\t\tgateway = {\n\t\t\tgetReferencesLists: function () {},\n\t\t\tgetReferencesList: function () {}\n\t\t},\n\t\tpage = new Page( { title: 'Foo' } ),\n\t\tresult;\n\n\tresult = lazyReferencesLoader.loadReferences( eventBus, {\n\t\texpanded: true,\n\t\tpage: page,\n\t\tisReferenceSection: true,\n\t\t$heading: $content.find( '#Notes_and_references' ).parent()\n\t}, gateway, page );\n\tassert.strictEqual( result, undefined );\n} );\n\nQUnit.test( '#getSectionId', function ( assert ) {\n\tvar\n\t\t$el = util.parseHTML(\n\t\t\t[\n\t\t\t\t'<div>',\n\t\t\t\t'<h2><span class=\"mw-headline\" id=\"heading\">H</span></h2>',\n\t\t\t\t'<div>',\n\t\t\t\t'<h3><span class=\"mw-headline\" id=\"subheading\">Subh</span></h3>',\n\t\t\t\t'<a class=\"element\"></a>',\n\t\t\t\t'</div>',\n\t\t\t\t'</div>'\n\t\t\t].join( '' )\n\t\t),\n\t\t$elTwo = util.parseHTML(\n\t\t\t[\n\t\t\t\t'<div>',\n\t\t\t\t'<h2><span class=\"mw-headline\" id=\"Notes_and_references\">Notes and references</span></h2>',\n\t\t\t\t'<div>',\n\t\t\t\t'<h3 class=\"in-block\"><span class=\"mw-headline\" id=\"Notes\">Notes</span></h3>',\n\t\t\t\t'<div class=\"reflist\"><a class=\"element\"></a></div>',\n\t\t\t\t'</div>',\n\t\t\t\t'</div>'\n\t\t\t].join( '' )\n\t\t),\n\t\t$elThree = util.parseHTML(\n\t\t\t[\n\t\t\t\t'<div id=\"mw-content-text\">',\n\t\t\t\t'<h2><span class=\"mw-headline\" id=\"heading\">Heading</span></h2>',\n\t\t\t\t'<div><a class=\"element\"></a></div>',\n\t\t\t\t'</div>'\n\t\t\t].join( '' )\n\t\t),\n\t\t$elFour = util.parseHTML(\n\t\t\t[\n\t\t\t\t'<div id=\"mw-content-text\">',\n\t\t\t\t'<div><a class=\"element\"></a></div>'\n\t\t\t].join( '' )\n\t\t),\n\t\t$elFive = util.parseHTML(\n\t\t\t[\n\t\t\t\t'<div id=\"mw-content-text\">',\n\t\t\t\t'<h2><span class=\"mw-headline\" id=\"Foo\">Foo</span></h2>',\n\t\t\t\t'<div>',\n\t\t\t\t'<p>Foo content.</p>',\n\t\t\t\t'</div>',\n\t\t\t\t'<h2><span class=\"mw-headline\" id=\"Bar\">Bar</span></h2>',\n\t\t\t\t'<div class=\"reflist\"><a class=\"element\"></a></div>',\n\t\t\t\t'</div>',\n\t\t\t\t'</div>'\n\t\t\t].join( '' )\n\t\t);\n\n\tassert.strictEqual(\n\t\tlazyReferencesLoader.test.getSectionId( $el.find( '.element' ) ),\n\t\t'subheading'\n\t);\n\tassert.strictEqual(\n\t\tlazyReferencesLoader.test.getSectionId( $elTwo.find( '.element' ) ),\n\t\t'Notes',\n\t\t'https://phabricator.wikimedia.org/T146394'\n\t);\n\tassert.strictEqual(\n\t\tlazyReferencesLoader.test.getSectionId( $elThree.find( '.element' ) ),\n\t\t'heading'\n\t);\n\tassert.strictEqual(\n\t\tlazyReferencesLoader.test.getSectionId( $elFour.find( '.element' ) ),\n\t\tnull\n\t);\n\tassert.strictEqual(\n\t\tlazyReferencesLoader.test.getSectionId( $elFive.find( '.element' ) ),\n\t\t'Bar'\n\t);\n} );\n","var mfExtend,\n\tsinon = require( 'sinon' ),\n\too = require( '../utils/oo' );\n\n/** @type {sinon.SinonSandbox} */ var sandbox; // eslint-disable-line one-var\n\nQUnit.module( 'MobileFrontend mfExtend.test.js', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t\too.setUp( sandbox, global );\n\t\tmfExtend = require( '../../../src/mobile.startup/mfExtend' );\n\t},\n\tafterEach: function () { sandbox.restore(); }\n} );\n\nQUnit.test( 'mfExtend() - extending from constructor', function ( assert ) {\n\tfunction TestChild() {}\n\tfunction TestPrototype() {}\n\tmfExtend( TestChild, TestPrototype, {} );\n\tassert.strictEqual( TestChild.prototype instanceof TestPrototype, true );\n} );\n\nQUnit.test( 'mfExtend() - extending from object', function ( assert ) {\n\tvar testPrototype = new TestPrototype(),\n\t\ttestChild;\n\tfunction TestChild() {}\n\tfunction TestPrototype() {\n\t\tthis.protoMethod = function () {\n\t\t\treturn true;\n\t\t};\n\t}\n\tmfExtend( TestChild, testPrototype );\n\ttestChild = new TestChild();\n\tassert.strictEqual( testChild.protoMethod(), true );\n} );\n\nQUnit.test( 'mfExtend() - extending from constructor with overrides', function ( assert ) {\n\tvar testChild;\n\tfunction TestChild() {}\n\tfunction TestPrototype() {\n\t\tthis.protoMethod = function () {\n\t\t\treturn true;\n\t\t};\n\t}\n\tmfExtend( TestChild, TestPrototype, {\n\t\tprotoMethod: function () {\n\t\t\treturn false;\n\t\t}\n\t} );\n\ttestChild = new TestChild();\n\tassert.strictEqual( testChild.protoMethod(), false );\n} );\n","var\n\tModuleLoader,\n\too = require( '../utils/oo' ),\n\tsinon = require( 'sinon' );\n/** @type {sinon.SinonSandbox} */ var sandbox; // eslint-disable-line one-var\n\nQUnit.module( 'MobileFrontend ModuleLoader', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t\too.setUp( sandbox, global );\n\n\t\tModuleLoader = require( '../../../src/mobile.startup/moduleLoader' );\n\t\tthis.loader = new ModuleLoader();\n\t},\n\tafterEach: function () { sandbox.restore(); }\n} );\n\nQUnit.test( '#require', function ( assert ) {\n\tthis.loader.define( 'foo', 1 );\n\tthis.loader.define( 'bar', 5 );\n\n\tassert.strictEqual( this.loader.require( 'foo' ), 1, 'Returns appropriate module' );\n\tassert.strictEqual( this.loader.require( 'bar' ), 5, 'Returns appropriate module' );\n\n\tassert.throws( function () {\n\t\tthis.loader.require( 'undefinedmodule' );\n\t}, 'Cannot require an undefined module.' );\n\tassert.throws( function () {\n\t\tthis.loader.require( 'mobile.modules/Foo' );\n\t}, 'Cannot require an undefined export on a known module.' );\n} );\n\nQUnit.test( '#define', function ( assert ) {\n\tvar loader = this.loader;\n\tloader.define( 'foo', 1 );\n\tloader.define( 'bar', 5 );\n\tassert.throws( function () {\n\t\tloader.define( 'bar', 50 );\n\t}, 'Cannot define two modules with the same name' );\n\tassert.strictEqual( this.loader.require( 'bar' ), 5, 'Returns first definition of module.' );\n} );\n","var promisedView, View,\n\tsandbox, happyView,\n\tutil = require( '../../../src/mobile.startup/util' ),\n\tjQuery = require( '../utils/jQuery' ),\n\tdom = require( '../utils/dom' ),\n\too = require( '../utils/oo' ),\n\tmediaWiki = require( '../utils/mw' ),\n\tsinon = require( 'sinon' );\n\nQUnit.module( 'MobileFrontend promisedView.js', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\too.setUp( sandbox, global );\n\t\tmediaWiki.setUp( sandbox, global );\n\t\tView = require( './../../../src/mobile.startup/View' );\n\t\tpromisedView = require( './../../../src/mobile.startup/promisedView' );\n\t\thappyView = new View( {\n\t\t\tisBorderBox: false,\n\t\t\tclassName: 'test'\n\t\t} );\n\t\thappyView.append( '😃' );\n\t\tsandbox.stub( mw, 'msg' ).withArgs( 'mobile-frontend-loading-message' ).returns( '⌛' );\n\t},\n\tafterEach: function () {\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( '#constructor happyView', function ( assert ) {\n\tvar promise = util.Deferred(),\n\t\tviewSuccess = promisedView( promise );\n\n\tassert.strictEqual( viewSuccess.$el.text(), '⌛', 'the view is waiting to resolve' );\n\tassert.ok( viewSuccess.$el.hasClass( 'promised-view' ), 'parent element has loading class when loading' );\n\tpromise.resolve( happyView );\n\treturn promise.then( function () {\n\t\tassert.strictEqual( viewSuccess.$el.attr( 'class' ), 'test', 'fully replaces its parent element with happyView\\'s parent element' );\n\t\tassert.strictEqual( viewSuccess.$el.text(), '😃', 'the view resolved correctly' );\n\t} );\n} );\n\nQUnit.test( '#constructor when promise rejects but not to a sadView', function ( assert ) {\n\tvar\n\t\tpromise = util.Deferred().reject( new Error( 'fake test error' ) ),\n\t\tviewFailure = promisedView( promise );\n\n\tassert.strictEqual( viewFailure.$el.text(), '⌛', 'the view is waiting to resolve' );\n\tassert.ok( viewFailure.$el.hasClass( 'promised-view' ), 'parent element has loading class when loading' );\n\n\treturn promise.catch( function () {\n\t\tassert.strictEqual( viewFailure.$el.text(), '⌛', 'the view still shows the loading icon' );\n\t} );\n} );\n\nQUnit.test( '#constructor when promise rejects to a sadView', function ( assert ) {\n\tvar\n\t\tsadView = new View( {\n\t\t\tisBorderBox: false,\n\t\t\tclassName: 'error'\n\t\t} ),\n\t\tpromise = util.Deferred().reject( sadView ),\n\t\tviewFailure = promisedView( promise );\n\n\tsadView.append( '😭' );\n\n\tassert.strictEqual( viewFailure.$el.text(), '⌛', 'the view is waiting to resolve' );\n\tassert.ok( viewFailure.$el.hasClass( 'promised-view' ), 'parent element has loading class when loading' );\n\n\treturn promise.catch( function () {\n\t\tassert.strictEqual( viewFailure.$el.attr( 'class' ), 'error', 'fully replaces its parent element with sadView\\'s parent element' );\n\t\tassert.strictEqual( viewFailure.$el.text(), '😭', 'the view resolved correctly' );\n\t} );\n} );\n","var sandbox, page, gateway, drawer,\n\tReferenceDrawer, Page,\n\tsinon = require( 'sinon' ),\n\too = require( '../../utils/oo' ),\n\tdom = require( '../../utils/dom' ),\n\tjQuery = require( '../../utils/jQuery' ),\n\tmediaWiki = require( '../../utils/mw' ),\n\tutil = require( '../../../../src/mobile.startup/util' ),\n\tReferencesGateway = require( '../../../../src/mobile.startup/references/ReferencesGateway' );\n\nQUnit.module( 'MobileFrontend: ReferencesDrawer', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\too.setUp( sandbox, global );\n\t\tmediaWiki.setUp( sandbox, global );\n\t\tPage = require( '../../../../src/mobile.startup/Page' );\n\t\tReferenceDrawer = require( '../../../../src/mobile.startup/references/ReferencesDrawer' );\n\t\tgateway = {\n\t\t\tgetReference: function () {}\n\t\t};\n\t\tpage = new Page( { title: 'reference test' } );\n\t\tdrawer = new ReferenceDrawer( {\n\t\t\tpage: page,\n\t\t\tgateway: gateway\n\t\t} );\n\t},\n\tafterEach: function () {\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( 'Bad reference not shown', function ( assert ) {\n\tvar promise = util.Deferred().reject( ReferencesGateway.ERROR_NOT_EXIST ).promise(),\n\t\thideSpy = sandbox.spy( drawer, 'hide' );\n\n\tsandbox.stub( gateway, 'getReference' ).returns( promise );\n\tdrawer.showReference( '#cite_note-bad', page, '1' );\n\n\treturn promise.catch( function () {\n\t\tassert.strictEqual( hideSpy.callCount, 1, 'Hide is called.' );\n\t} );\n} );\n\nQUnit.test( 'Good reference causes render', function ( assert ) {\n\tvar promise = util.Deferred().resolve( {\n\t\t\ttext: 'I am a reference'\n\t\t} ).promise(),\n\t\trenderSpy = sandbox.spy( drawer, 'render' ),\n\t\tshowSpy = sandbox.spy( drawer, 'show' ),\n\t\tdone = assert.async();\n\n\tsandbox.stub( gateway, 'getReference' ).returns( promise );\n\tdrawer.showReference( '#cite_note-good', page, '1' );\n\n\treturn promise.then( function () {\n\t\tassert.strictEqual( showSpy.callCount, 1, 'Show is called.' );\n\t\tassert.strictEqual( renderSpy.callCount, 1, 'Render is called.' );\n\t\tdone();\n\t} );\n} );\n\nQUnit.test( 'Reference failure renders error in drawer', function ( assert ) {\n\tvar promise = util.Deferred().reject( ReferencesGateway.ERROR_OTHER ).promise(),\n\t\trenderSpy = sandbox.spy( drawer, 'render' ),\n\t\tshowSpy = sandbox.spy( drawer, 'show' ),\n\t\tdone = assert.async();\n\n\tsandbox.stub( gateway, 'getReference' ).returns( promise );\n\tdrawer.showReference( '#cite_note-bad', page, '1' );\n\n\treturn promise.catch( function () {\n\t\tassert.strictEqual( showSpy.callCount, 1, 'Show is called.' );\n\t\tassert.strictEqual( renderSpy.callCount, 1, 'Render is called.' );\n\t\tassert.ok( renderSpy.calledWith( {\n\t\t\terror: true,\n\t\t\ttitle: '1',\n\t\t\ttext: mw.msg( 'mobile-frontend-references-citation-error' )\n\t\t} ), 'Render is called with the error parameter.' );\n\t\tdone();\n\t} );\n} );\n","var page, referencesGateway,\n\tsandbox, Page, ReferencesHtmlScraperGateway,\n\tsinon = require( 'sinon' ),\n\tReferencesGateway = require( './../../../../src/mobile.startup/references/ReferencesGateway' ),\n\treferencesPage = require( '../../utils/PageInputs.html' ).referencesPage,\n\tutil = require( '../../../../src/mobile.startup/util' ),\n\too = require( '../../utils/oo' ),\n\tdom = require( '../../utils/dom' ),\n\tjQuery = require( '../../utils/jQuery' ),\n\tmediaWiki = require( '../../utils/mw' );\n\nQUnit.module( 'MobileFrontend ReferencesHtmlScraperGateway.test.js', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\too.setUp( sandbox, global );\n\t\tmediaWiki.setUp( sandbox, global );\n\t\tPage = require( '../../../../src/mobile.startup/Page' );\n\t\tReferencesHtmlScraperGateway = require( './../../../../src/mobile.startup/references/ReferencesHtmlScraperGateway' );\n\t\tpage = new Page( {\n\t\t\tel: util.parseHTML( '<div>' ).html( referencesPage ),\n\t\t\ttitle: 'Reftest'\n\t\t} );\n\t\treferencesGateway = new ReferencesHtmlScraperGateway( new mw.Api() );\n\t},\n\tafterEach: function () {\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( 'getReference() checking good reference', function ( assert ) {\n\treturn referencesGateway.getReference( '#cite_note-1', page ).then( function ( ref ) {\n\t\tassert.strictEqual( util.parseHTML( '<div>' ).html( ref.text ).find( '.reference-text' ).text(), 'hello' );\n\t} );\n} );\n\nQUnit.test( 'getReference() checking bad reference', function ( assert ) {\n\treturn referencesGateway.getReference( '#cite_note-bad', page ).catch( function ( err ) {\n\t\tassert.strictEqual( err, ReferencesGateway.ERROR_NOT_EXIST, 'When bad id given false returned.' );\n\t} );\n} );\n\nQUnit.test( 'getReference() checking encoded reference', function ( assert ) {\n\tvar id = '#cite_note-Obama_1995,_2004,_pp._9%E2%80%9310-11';\n\treturn referencesGateway.getReference( id, page ).then( function ( ref ) {\n\t\tassert.strictEqual( util.parseHTML( '<div>' ).html( ref.text ).find( '.reference-text' ).text(), 'found',\n\t\t\t'If an encoded ID parameter is given it still resolves correctly.' );\n\t} );\n} );\n","var referencesGatewayRejector, referencesGatewayEmpty, page, api, referencesGateway,\n\tsandbox, ReferencesMobileViewGateway, Page,\n\tsinon = require( 'sinon' ),\n\tReferencesGateway = require( './../../../../src/mobile.startup/references/ReferencesGateway' ),\n\tutil = require( '../../../../src/mobile.startup/util' ),\n\tmediaWiki = require( '../../utils/mw' ),\n\too = require( '../../utils/oo' ),\n\tjQuery = require( '../../utils/jQuery' ),\n\tdom = require( '../../utils/dom' ),\n\tlazyLoadedReferencesPage = require( '../../utils/PageInputs.html' ).lazyLoadedReferencesPage,\n\tcache = require( '../../../../src/mobile.startup/cache' ),\n\tMemoryCache = cache.MemoryCache;\n\nQUnit.module( 'MobileFrontend ReferencesMobileViewGateway.test.js', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\too.setUp( sandbox, global );\n\t\tmediaWiki.setUp( sandbox, global );\n\t\tReferencesMobileViewGateway = require( './../../../../src/mobile.startup/references/ReferencesMobileViewGateway' );\n\t\tPage = require( '../../../../src/mobile.startup/Page' );\n\n\t\tpage = new Page( {\n\t\t\tel: util.parseHTML( lazyLoadedReferencesPage ),\n\t\t\ttitle: 'Reftest'\n\t\t} );\n\n\t\tapi = new mw.Api();\n\t\tsandbox.stub( api, 'get' ).returns(\n\t\t\tutil.Deferred().resolve( {\n\t\t\t\tmobileview: {\n\t\t\t\t\tsections: []\n\t\t\t\t}\n\t\t\t} )\n\t\t);\n\n\t\treferencesGateway = new ReferencesMobileViewGateway( new mw.Api() );\n\t\tsandbox.stub( referencesGateway, 'getReferencesLists' ).returns(\n\t\t\tutil.Deferred().resolve( {\n\t\t\t\t1: '<ol class=\"references\"><li id=\"cite_note-1\">real lazy</li>' +\n\t\t\t\t\t'<li id=\"cite_note-2\">real lazy 2</li></ol>'\n\t\t\t} ).promise()\n\t\t);\n\t\treferencesGatewayEmpty = new ReferencesMobileViewGateway( new mw.Api() );\n\t\tsandbox.stub( referencesGatewayEmpty, 'getReferencesLists' ).returns(\n\t\t\tutil.Deferred().resolve( {} ).promise()\n\t\t);\n\t\treferencesGatewayRejector = new ReferencesMobileViewGateway( new mw.Api() );\n\t\tsandbox.stub( referencesGatewayRejector, 'getReferencesLists' ).returns(\n\t\t\tutil.Deferred().reject( ReferencesGateway.ERROR_OTHER ).promise()\n\t\t);\n\t},\n\tafterEach: function () {\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( 'getReferencesLists() Gateway only hits api once despite multiple calls', function ( assert ) {\n\tvar gatewayHitsApi = new ReferencesMobileViewGateway( api, new MemoryCache() );\n\treturn gatewayHitsApi.getReferencesLists( page ).then( function () {\n\t\tgatewayHitsApi.getReferencesLists( page );\n\t\tgatewayHitsApi.getReferencesLists( page );\n\t\tassert.strictEqual( api.get.calledOnce, true, 'The API should only ever be hit once.' );\n\t} );\n} );\n\nQUnit.test( 'getReference() checking good reference', function ( assert ) {\n\treturn referencesGateway.getReference( '#cite_note-1', page ).then( function ( ref ) {\n\t\tassert.strictEqual( ref.text, 'real lazy' );\n\t} );\n} );\n\nQUnit.test( 'getReference() checking good reference (subsequent calls)', function ( assert ) {\n\treturn referencesGateway.getReference( '#cite_note-1', page ).then( function () {\n\t\treturn referencesGateway.getReference( '#cite_note-2', page ).then( function ( ref ) {\n\t\t\tassert.strictEqual( ref.text, 'real lazy 2' );\n\t\t} );\n\t} );\n} );\n\nQUnit.test( 'getReference() checking bad reference', function ( assert ) {\n\treturn referencesGateway.getReference( '#cite_note-bad', page ).catch( function ( err ) {\n\t\tassert.strictEqual( err, ReferencesGateway.ERROR_NOT_EXIST,\n\t\t\t'When reference not found error message reflects that.' );\n\t} );\n} );\n\nQUnit.test( 'getReference() checking reference on non-existent page', function ( assert ) {\n\treturn referencesGatewayEmpty.getReference( '#cite_note-bad', page ).catch( function ( err ) {\n\t\tassert.strictEqual( err, ReferencesGateway.ERROR_NOT_EXIST,\n\t\t\t'When getReferencesElement returns empty list of elements reference is false.' );\n\t} );\n} );\n\nQUnit.test( 'getReference() checking reference when gateway rejects', function ( assert ) {\n\treturn referencesGatewayRejector.getReference( '#cite_note-bad-2', page ).catch( function ( err ) {\n\t\tassert.strictEqual( err, ReferencesGateway.ERROR_OTHER, 'getReference is rejected if API query fails' );\n\t} );\n} );\n","var\n\tsinon = require( 'sinon' ),\n\tdom = require( '../utils/dom' ),\n\tjQuery = require( '../utils/jQuery' ),\n\too = require( '../utils/oo' ),\n\tmediaWiki = require( '../utils/mw' ),\n\tutil = require( '../../../src/mobile.startup/util' ),\n\trlModuleLoader,\n\tsandbox;\n\nfunction assertShowHideWorksWhenSuccessful( assert, firstArg, secondArg, thirdArg ) {\n\tvar\n\t\tself = this,\n\t\tresult;\n\n\tsandbox.stub( rlModuleLoader, 'newLoadingOverlay' ).returns( this.stub );\n\n\tresult = rlModuleLoader.loadModule( firstArg, secondArg, thirdArg );\n\n\tassert.strictEqual( this.stub.show.callCount, 1, 'LoadingOverlay show() called once' );\n\tassert.strictEqual( this.stub.show.getCall( 0 ).args.length, 0, 'LoadingOverlay show() called with no args' );\n\tassert.strictEqual( this.stub.hide.callCount, 0, 'LoadingOverlay hide not called' );\n\n\tthis.deferred.resolve();\n\n\treturn result.then( function ( overlay ) {\n\t\tassert.strictEqual( overlay, self.stub, 'Promise resolves to overlay instance' );\n\t\tassert.strictEqual( self.stub.show.callCount, 1, 'LoadingOverlay show() called once' );\n\t\tassert.strictEqual( self.stub.hide.callCount, 1, 'LoadingOverlay hide() called once' );\n\t\tassert.strictEqual( self.stub.hide.getCall( 0 ).args.length, 0, 'LoadingOverlay hide() called with no args' );\n\t} );\n}\n\nQUnit.module( 'MobileFrontend rlModuleLoader.js', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\too.setUp( sandbox, global );\n\t\tmediaWiki.setUp( sandbox, global );\n\t\trlModuleLoader = require( '../../../src/mobile.startup/rlModuleLoader' );\n\n\t\t// jsdom will throw \"Not implemented\" errors if we don't stub\n\t\t// window.scrollTo\n\t\tsandbox.stub( global.window, 'scrollTo' );\n\n\t\tthis.stub = {\n\t\t\tappendTo: sandbox.spy(),\n\t\t\tshow: sandbox.spy(),\n\t\t\thide: sandbox.spy()\n\t\t};\n\t\tthis.deferred = util.Deferred();\n\n\t\tsandbox.stub( mw.loader, 'using' )\n\t\t\t.withArgs( 'mobile.mediaViewer' )\n\t\t\t.returns( this.deferred );\n\n\t},\n\tafterEach: function () {\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( '#newLoadingOverlay does not blow up', function ( assert ) {\n\tassert.expect( 0 );\n\n\trlModuleLoader.newLoadingOverlay();\n} );\n\nQUnit.test( '#loadModule when instructed to show/hide overlay and successful', function ( assert ) {\n\treturn assertShowHideWorksWhenSuccessful.apply( this, [ assert, 'mobile.mediaViewer', false, true ] );\n} );\n\nQUnit.test( '#loadModule when instructed to show/hide overlay (default args) and successful', function ( assert ) {\n\treturn assertShowHideWorksWhenSuccessful.apply( this, [ assert, 'mobile.mediaViewer', false ] );\n} );\n\nQUnit.test( '#loadModule when instructed to show/hide overlay and not successful', function ( assert ) {\n\tvar\n\t\tself = this,\n\t\tresult;\n\n\tsandbox.stub( rlModuleLoader, 'newLoadingOverlay' ).returns( this.stub );\n\n\tresult = rlModuleLoader.loadModule( 'mobile.mediaViewer', false, true );\n\n\tthis.deferred.reject();\n\n\tassert.rejects( result, 'returned promise rejects' );\n\treturn result.catch( function () {\n\t\tassert.strictEqual( self.stub.show.callCount, 1, 'LoadingOverlay show() called once' );\n\t\tassert.strictEqual( self.stub.appendTo.callCount, 1, 'LoadingOverlay appendTo() called once' );\n\t\tassert.strictEqual( self.stub.hide.callCount, 1, 'LoadingOverlay hide() called once' );\n\t\tassert.strictEqual( self.stub.hide.getCall( 0 ).args.length, 0, 'LoadingOverlay hide() called with no args' );\n\t} );\n} );\n\nQUnit.test( '#loadModule when instructed to show/not hide overlay and successful', function ( assert ) {\n\tvar\n\t\tself = this,\n\t\tresult;\n\n\tsandbox.stub( rlModuleLoader, 'newLoadingOverlay' ).returns( this.stub );\n\n\tresult = rlModuleLoader.loadModule( 'mobile.mediaViewer', true, true );\n\n\tassert.strictEqual( this.stub.show.callCount, 1, 'LoadingOverlay show() called once' );\n\tassert.strictEqual( this.stub.show.getCall( 0 ).args.length, 0, 'LoadingOverlay show() called with no args' );\n\tassert.strictEqual( this.stub.hide.callCount, 0, 'LoadingOverlay hide() not called' );\n\n\tthis.deferred.resolve();\n\n\treturn result.then( function ( overlay ) {\n\t\tassert.strictEqual( overlay, self.stub, 'Promise resolves to overlay instance' );\n\t\tassert.strictEqual( self.stub.show.callCount, 1, 'LoadingOverlay show() called once' );\n\t\tassert.strictEqual( self.stub.hide.callCount, 0, 'LoadingOverlay hide() not called' );\n\t} );\n} );\n\nQUnit.test( '#loadModule when instructed to show/not hide overlay and not successful', function ( assert ) {\n\tvar\n\t\tself = this,\n\t\tresult;\n\n\tsandbox.stub( rlModuleLoader, 'newLoadingOverlay' ).returns( this.stub );\n\n\tresult = rlModuleLoader.loadModule( 'mobile.mediaViewer', true, true );\n\n\tthis.deferred.reject();\n\n\tassert.rejects( result, 'returned promise rejects' );\n\treturn result.catch( function () {\n\t\tassert.strictEqual( self.stub.show.callCount, 1, 'LoadingOverlay show() called once' );\n\t\tassert.strictEqual( self.stub.hide.callCount, 0, 'LoadingOverlay hide() not called' );\n\t} );\n} );\n\nQUnit.test( '#loadModule when instructed to not show overlay and successful', function ( assert ) {\n\tvar\n\t\tself = this,\n\t\tresult;\n\n\tsandbox.stub( rlModuleLoader, 'newLoadingOverlay' ).returns( this.stub );\n\n\tresult = rlModuleLoader.loadModule( 'mobile.mediaViewer', false, false );\n\n\tassert.strictEqual( this.stub.show.callCount, 0, 'LoadingOverlay show() not called' );\n\tassert.strictEqual( this.stub.hide.callCount, 0, 'LoadingOverlay hide() not called' );\n\n\tthis.deferred.resolve();\n\n\treturn result.then( function ( overlay ) {\n\t\tassert.strictEqual( overlay, self.stub, 'Promise resolves to overlay instance' );\n\t\tassert.strictEqual( self.stub.show.callCount, 0, 'LoadingOverlay show() not called' );\n\t\tassert.strictEqual( self.stub.hide.callCount, 0, 'LoadingOverlay hide() not called' );\n\t} );\n} );\n\nQUnit.test( '#loadModule when instructed to not show overlay and not successful', function ( assert ) {\n\tvar\n\t\tself = this,\n\t\tresult;\n\n\tsandbox.stub( rlModuleLoader, 'newLoadingOverlay' ).returns( this.stub );\n\n\tresult = rlModuleLoader.loadModule( 'mobile.mediaViewer', false, false );\n\n\tthis.deferred.reject();\n\n\tassert.rejects( result, 'returned promise rejects' );\n\treturn result.catch( function () {\n\t\tassert.strictEqual( self.stub.show.callCount, 0, 'LoadingOverlay show() not called' );\n\t\tassert.strictEqual( self.stub.hide.callCount, 0, 'LoadingOverlay hide() not called' );\n\t} );\n} );\n","var\n\tsinon = require( 'sinon' ),\n\tmediawiki = require( '../../utils/mw' ),\n\tMobileWebSearchLogger = require( '../../../../src/mobile.startup/search/MobileWebSearchLogger' );\n/** @type {sinon.SinonSandbox} */ var sandbox; // eslint-disable-line one-var\n\nQUnit.module( 'MobileFrontend: MobileWebSearchLogger', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t\tmediawiki.setUp( sandbox, global );\n\n\t\tthis.logger = new MobileWebSearchLogger();\n\t\tthis.spy = sandbox.stub( mw, 'track' );\n\t},\n\n\tafterEach: function () {\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( 'it should log when the search is shown', function ( assert ) {\n\tvar self = this;\n\n\t// The user opens the search overlay.\n\tthis.logger.onSearchShow();\n\tthis.logger.onSearchStart();\n\n\tassert.ok( this.spy.calledWith( 'mf.schemaMobileWebSearch', {\n\t\taction: 'session-start',\n\t\tuserSessionToken: self.logger.userSessionToken,\n\t\tsearchSessionToken: self.logger.searchSessionToken,\n\t\ttimeOffsetSinceStart: 0\n\t} ), 'Search start is logged correctly.' );\n} );\n\nQUnit.test( 'it should log when the search API request completes', function ( assert ) {\n\tvar data;\n\n\t// The user opens the search overlay, searches for a term, and is shown\n\t// results.\n\tthis.logger.onSearchShow();\n\tthis.logger.onSearchStart();\n\tthis.logger.onSearchResults( {\n\t\tresults: [ 'result1', 'result2' ]\n\t} );\n\n\tdata = mw.track.getCall( 1 ).args[1];\n\n\tassert.strictEqual( data.action, 'impression-results' );\n\tassert.strictEqual( data.resultSetType, 'prefix' );\n\tassert.strictEqual( data.numberOfResults, 2 );\n\tassert.strictEqual( data.userSessionToken, this.logger.userSessionToken );\n\tassert.strictEqual( data.searchSessionToken, this.logger.searchSessionToken );\n} );\n\nQUnit.test( 'it should refresh the user session token when the search is shown again', function ( assert ) {\n\t// The user opens the search overlay, searches for a term, closes the\n\t// search overlay, opens the search overlay, and searches for a term.\n\tthis.logger.onSearchShow();\n\tthis.logger.onSearchStart();\n\tthis.logger.onSearchShow();\n\tthis.logger.onSearchStart();\n\n\tassert.notStrictEqual(\n\t\tmw.track.getCall( 0 ).args[1].userSessionToken,\n\t\tmw.track.getCall( 1 ).args[1].userSessionToken\n\t);\n} );\n\nQUnit.test( 'it should log when the user clicks a result', function ( assert ) {\n\tvar data;\n\n\t// The user opens the search overlay, searches for a term, is shown\n\t// results, and clicks a result.\n\tthis.logger.onSearchShow();\n\tthis.logger.onSearchStart();\n\tthis.logger.onSearchResults( {\n\t\tresults: []\n\t} );\n\n\t// The user clicks the first result.\n\tthis.logger.onSearchResultClick( {\n\t\tresultIndex: 0\n\t} );\n\n\tdata = mw.track.getCall( 2 ).args[1];\n\n\tassert.strictEqual( data.action, 'click-result' );\n\tassert.strictEqual( data.clickIndex, 1 );\n} );\n\nQUnit.test( 'it should refresh the search session token when the search API request completes again', function ( assert ) {\n\tvar event = {\n\t\tresults: []\n\t};\n\n\t// The user opens the search overlay, searches for a term, is shown\n\t// results, searches for another term, and is shown results.\n\tthis.logger.onSearchShow();\n\tthis.logger.onSearchStart();\n\tthis.logger.onSearchResults( event );\n\tthis.logger.onSearchStart();\n\tthis.logger.onSearchResults( event );\n\n\tassert.notStrictEqual(\n\t\tmw.track.getCall( 1 ).args[1].searchSessionToken,\n\t\tmw.track.getCall( 3 ).args[1].searchSessionToken\n\t);\n} );\n","var\n\tjQuery = require( '../../utils/jQuery' ),\n\tdom = require( '../../utils/dom' ),\n\tmediaWiki = require( '../../utils/mw' ),\n\too = require( '../../utils/oo' ),\n\tSearchGateway,\n\tsandbox,\n\tsinon = require( 'sinon' ),\n\tutil = require( '../../../../src/mobile.startup/util' );\n\nQUnit.module( 'MobileFrontend: SearchGateway',\n\t{\n\t\tbeforeEach: function () {\n\t\t\tsandbox = sinon.sandbox.create();\n\t\t\tdom.setUp( sandbox, global );\n\t\t\tjQuery.setUp( sandbox, global );\n\t\t\too.setUp( sandbox, global );\n\n\t\t\t// Additional CtaDrawer global dependency.\n\t\t\tmediaWiki.setUp( sandbox, global );\n\n\t\t\tSearchGateway = require( '../../../../src/mobile.startup/search/SearchGateway' );\n\n\t\t\tsandbox.stub( mw.util, 'getUrl' ).returns( 'Title' );\n\t\t\tsandbox.stub( mw.config, 'get', function ( name ) {\n\t\t\t\tswitch ( name ) {\n\t\t\t\t\tcase 'wgMFDisplayWikibaseDescriptions': return { search: '' };\n\t\t\t\t\tcase 'wgMFSearchGenerator': return { prefix: '' };\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\tthis.gateway = new SearchGateway( new mw.Api() );\n\t\t\tsandbox.stub( this.gateway.api, 'get', function () {\n\t\t\t\treturn util.Deferred().resolve( {\n\t\t\t\t\twarnings: {\n\t\t\t\t\t\tquery: {\n\t\t\t\t\t\t\t'*': 'Formatting of continuation data will be changing soon. To continue using the current formatting, use the \"rawcontinue\" parameter. To begin using the new format, pass an empty string for \"continue\" in the initial query.'\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\tquery: {\n\t\t\t\t\t\tpages: {\n\t\t\t\t\t\t\t2: {\n\t\t\t\t\t\t\t\tindex: 1,\n\t\t\t\t\t\t\t\tpageid: 2,\n\t\t\t\t\t\t\t\tns: 0,\n\t\t\t\t\t\t\t\ttitle: 'Claude Monet',\n\t\t\t\t\t\t\t\tthumbnail: {\n\t\t\t\t\t\t\t\t\tsource: 'http://127.0.0.1:8080/images/thumb/5/54/Claude_Monet%2C_Impression%2C_soleil_levant.jpg/80px-Claude_Monet%2C_Impression%2C_soleil_levant.jpg',\n\t\t\t\t\t\t\t\t\twidth: 80,\n\t\t\t\t\t\t\t\t\theight: 62\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t60: {\n\t\t\t\t\t\t\t\tindex: 2,\n\t\t\t\t\t\t\t\tpageid: 60,\n\t\t\t\t\t\t\t\tns: 0,\n\t\t\t\t\t\t\t\ttitle: 'Barack Obama',\n\t\t\t\t\t\t\t\tthumbnail: {\n\t\t\t\t\t\t\t\t\tsource: 'http://127.0.0.1:8080/images/thumb/8/8d/President_Barack_Obama.jpg/64px-President_Barack_Obama.jpg',\n\t\t\t\t\t\t\t\t\twidth: 64,\n\t\t\t\t\t\t\t\t\theight: 80\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t} );\n\t\t},\n\n\t\tafterEach: function () {\n\t\t\tSearchGateway = undefined;\n\t\t\tjQuery.tearDown();\n\t\t\tsandbox.restore();\n\t\t}\n\t},\n\tfunction () {\n\t\tQUnit.test( '._highlightSearchTerm', function ( assert ) {\n\t\t\tvar data,\n\t\t\t\tgateway = this.gateway;\n\n\t\t\tdata = [\n\t\t\t\t[ 'Hello World', 'Hel', '<strong>Hel</strong>lo World' ],\n\t\t\t\t[ 'Hello kitty', 'el', 'Hello kitty' ], // not at start\n\t\t\t\t[ 'Hello worl', 'hel', '<strong>Hel</strong>lo worl' ],\n\t\t\t\t[ 'Belle & Sebastian', 'Belle & S', '<strong>Belle &amp; S</strong>ebastian' ],\n\t\t\t\t[ 'Belle & the Beast', 'Belle &amp;', 'Belle &amp; the Beast' ],\n\t\t\t\t[ 'with ? in it', 'with ?', '<strong>with ?</strong> in it' ], // not at start\n\t\t\t\t[ 'Title with ? in it', 'with ?', 'Title with ? in it' ], // not at start\n\t\t\t\t[ 'AT&T', 'a', '<strong>A</strong>T&amp;T' ],\n\t\t\t\t[ 'AT&T', 'at&', '<strong>AT&amp;</strong>T' ],\n\t\t\t\t[ '<tag', '&lt;tag', '&lt;tag' ],\n\t\t\t\t[ '& this is a weird title', '&', '<strong>&amp;</strong> this is a weird title' ],\n\t\t\t\t[ '& this is a weird title', '&a', '&amp; this is a weird title' ],\n\t\t\t\t[ '&lt;t', '<t', '&amp;lt;t' ],\n\t\t\t\t[ '<script>alert(\"FAIL\")</script> should be safe',\n\t\t\t\t\t'<script>alert(\"FAIL\"', '<strong>&lt;script&gt;alert(\"FAIL\"</strong>)&lt;/script&gt; should be safe' ]\n\t\t\t];\n\t\t\tdata.forEach( function ( item, i ) {\n\t\t\t\tassert.strictEqual( gateway._highlightSearchTerm( item[ 0 ], item[ 1 ] ), item[ 2 ], 'highlightSearchTerm test ' + i );\n\t\t\t} );\n\t\t} );\n\n\t\tQUnit.test( 'show redirect targets', function ( assert ) {\n\t\t\treturn this.gateway.search( 'barack' ).then( function ( response ) {\n\t\t\t\tassert.strictEqual( response.query, 'barack' );\n\t\t\t\tassert.strictEqual( response.results.length, 2 );\n\t\t\t\tassert.strictEqual( response.results[ 0 ].displayTitle, 'Claude Monet' );\n\t\t\t\tassert.strictEqual( response.results[ 0 ].thumbnail.width, 80 );\n\t\t\t\tassert.strictEqual( response.results[ 1 ].displayTitle, '<strong>Barack</strong> Obama' );\n\t\t\t\tassert.strictEqual( response.results[ 1 ].title, 'Barack Obama' );\n\t\t\t} );\n\t\t} );\n\n\t\tQUnit.module( 'MobileFrontend SearchGateway (Wikidata Descriptions)', {\n\t\t\tbeforeEach: function () {\n\t\t\t\tvar data = {\n\t\t\t\t\tquery: {\n\t\t\t\t\t\tpages: {\n\t\t\t\t\t\t\t2: {\n\t\t\t\t\t\t\t\tpageid: 2,\n\t\t\t\t\t\t\t\tns: 0,\n\t\t\t\t\t\t\t\ttitle: 'Brad Pitt',\n\t\t\t\t\t\t\t\tindex: 2,\n\t\t\t\t\t\t\t\tdescription: 'American actor'\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t4: {\n\t\t\t\t\t\t\t\tpageid: 4,\n\t\t\t\t\t\t\t\tns: 0,\n\t\t\t\t\t\t\t\ttitle: 'Bradley Cooper',\n\t\t\t\t\t\t\t\tindex: 3,\n\t\t\t\t\t\t\t\tdescription: 'American actor and film producer'\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t5: {\n\t\t\t\t\t\t\t\tpageid: 5,\n\t\t\t\t\t\t\t\tns: 0,\n\t\t\t\t\t\t\t\ttitle: 'Braddy',\n\t\t\t\t\t\t\t\tindex: 1\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\tsandbox.stub( mw.Api.prototype, 'get' ).returns( util.Deferred().resolve( data ) );\n\t\t\t}\n\t\t} );\n\n\t\tQUnit.test( 'Wikidata Description in search results', function ( assert ) {\n\t\t\tvar searchApi = new SearchGateway( new mw.Api() );\n\t\t\treturn searchApi.search( 'brad' ).then( function ( resp ) {\n\t\t\t\tvar results = resp.results;\n\t\t\t\tassert.strictEqual(\n\t\t\t\t\tresults[0].wikidataDescription,\n\t\t\t\t\tundefined,\n\t\t\t\t\t'Braddy does not have a Wikidata description.'\n\t\t\t\t);\n\t\t\t\tassert.strictEqual(\n\t\t\t\t\tresults[1].wikidataDescription,\n\t\t\t\t\t'American actor',\n\t\t\t\t\t'Yes, Brad Pitt is an actor.'\n\t\t\t\t);\n\t\t\t\tassert.strictEqual(\n\t\t\t\t\tresults[2].wikidataDescription,\n\t\t\t\t\t'American actor and film producer',\n\t\t\t\t\t'Yes, Cooper is an actor.'\n\t\t\t\t);\n\t\t\t} );\n\t\t} );\n\t} );\n","var talkOverlay, sandbox, Overlay, PageGateway,\n\tjQuery = require( '../../utils/jQuery' ),\n\tutil = require( './../../../../src/mobile.startup/util' ),\n\tdom = require( '../../utils/dom' ),\n\tmediaWiki = require( '../../utils/mw' ),\n\too = require( '../../utils/oo' ),\n\tsinon = require( 'sinon' );\n\nQUnit.module( 'MobileFrontend mobile.talk.overlays/talkOverlay', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\too.setUp( sandbox, global );\n\t\tmediaWiki.setUp( sandbox, global );\n\n\t\tsandbox.stub( mw, 'msg' ).returns( 'msg-key' );\n\t\ttalkOverlay = require( '../../../../src/mobile.startup/talk/overlay' );\n\t\tOverlay = require( '../../../../src/mobile.startup/Overlay' );\n\t\tPageGateway = require( '../../../../src/mobile.startup/PageGateway' );\n\t},\n\tafterEach: function () {\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( 'talkOverlay add discussion button', function ( assert ) {\n\tvar userStub,\n\t\tgateway = new PageGateway( { api: {} } ),\n\t\tdeferred = util.Deferred().resolve( [] ),\n\t\tspy = sandbox.stub( Overlay, 'make' );\n\n\tsandbox.stub( gateway, 'getSections' ).returns( deferred );\n\tsandbox.stub( mw.loader, 'using' ).returns( deferred );\n\tuserStub = sandbox.stub( mw.user, 'isAnon' ).returns( true );\n\n\t// first call to spy as anon\n\ttalkOverlay( 'Foo', gateway );\n\n\t// second call to spy as logged in\n\tuserStub.restore();\n\tsandbox.stub( mw.user, 'isAnon' ).returns( false );\n\ttalkOverlay( 'overlay logged in', gateway );\n\tassert.propEqual(\n\t\tspy.args[1][0].headerButtons[0].href, '#/talk/new', 'logged in users have the add discussion button'\n\t);\n\tassert.propEqual( spy.args[0][0].headerButtons[0], {}, 'anons do not have the add discussion button' );\n\treturn deferred;\n} );\n","var time = require( '../../../src/mobile.startup/time' );\n\nQUnit.module( 'MobileFrontend time.js' );\n\nQUnit.test( 'timeAgo()', function ( assert ) {\n\tassert.propEqual( time.timeAgo( 40 ), {\n\t\tvalue: 40,\n\t\tunit: 'seconds'\n\t} );\n\tassert.propEqual( time.timeAgo( 149 ), {\n\t\tvalue: 2,\n\t\tunit: 'minutes'\n\t} );\n\tassert.propEqual( time.timeAgo( 150 ), {\n\t\tvalue: 3,\n\t\tunit: 'minutes'\n\t} );\n\tassert.propEqual( time.timeAgo( 7500 ), {\n\t\tvalue: 2,\n\t\tunit: 'hours'\n\t} );\n\tassert.propEqual( time.timeAgo( 90000 ), {\n\t\tvalue: 1,\n\t\tunit: 'days'\n\t} );\n\tassert.propEqual( time.timeAgo( 9000000 ), {\n\t\tvalue: 3,\n\t\tunit: 'months'\n\t} );\n\tassert.propEqual( time.timeAgo( 32000000 ), {\n\t\tvalue: 1,\n\t\tunit: 'years'\n\t} );\n\tassert.propEqual( time.timeAgo( 102000000 ), {\n\t\tvalue: 3,\n\t\tunit: 'years'\n\t} );\n} );\n","/* global $ */\nvar util,\n\tdom = require( '../utils/dom' ),\n\tmw = require( '../utils/mw' ),\n\tjQuery = require( '../utils/jQuery' ),\n\too = require( '../utils/oo' ),\n\tsinon = require( 'sinon' );\n\n/** @type {sinon.SinonSandbox} */ var sandbox; // eslint-disable-line one-var\n\nQUnit.module( 'MobileFrontend util.js', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t\tdom.setUp( sandbox, global );\n\t\tmw.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\too.setUp( sandbox, global );\n\t\tutil = require( '../../../src/mobile.startup/util' );\n\t},\n\tafterEach: function () {\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( 'Promise.all() success', function ( assert ) {\n\tvar p = util.Deferred(),\n\t\tp2 = util.Deferred();\n\n\tp.resolve( 'a' );\n\tp2.resolve( 'b' );\n\treturn util.Promise.all( [ p, p2 ] ).then( function ( result, result2 ) {\n\t\tassert.strictEqual( result, 'a', 'All promises resolved (yay)' );\n\t\tassert.strictEqual( result2, 'b', 'All promises resolved (yay)' );\n\t} );\n} );\n\nQUnit.test( 'Promise.all() reject', function ( assert ) {\n\tvar p = util.Deferred(),\n\t\tp2 = util.Deferred();\n\n\tp.resolve( 'a' );\n\tp2.reject( 'b' );\n\treturn util.Promise.all( [ p, p2 ] ).catch( function ( result ) {\n\t\tassert.strictEqual( result, 'b', 'The promise rejects' );\n\t} );\n} );\n\nQUnit.test( 'escapeSelector()', function ( assert ) {\n\tassert.strictEqual(\n\t\tutil.escapeSelector( '#selector-starts-with-hash' ),\n\t\t'\\\\#selector-starts-with-hash'\n\t);\n} );\n\nQUnit.test( 'grep()', function ( assert ) {\n\tassert.propEqual(\n\t\tutil.grep( [ 1, 2 ], function ( n ) {\n\t\t\treturn n > 1;\n\t\t} ),\n\t\t[ 2 ]\n\t);\n} );\n\nQUnit.test( 'docReady()', function ( assert ) {\n\tvar docReady = util.docReady();\n\tassert.strictEqual(\n\t\tdocReady instanceof $,\n\t\ttrue\n\t);\n} );\n\nQUnit.test( 'Deferred() - resolve', function ( assert ) {\n\tvar deferred = new util.Deferred(),\n\t\tresponse = 'response';\n\tdeferred.resolve( response );\n\treturn deferred.then( function ( res ) {\n\t\tassert.strictEqual( res, response );\n\t} );\n} );\n\nQUnit.test( 'Deferred() - reject', function ( assert ) {\n\tvar deferred = new util.Deferred(),\n\t\tresponse = 'response';\n\tdeferred.reject( response );\n\treturn deferred.catch( function ( error ) {\n\t\tassert.strictEqual( error, response );\n\t} );\n} );\nQUnit.test( 'getDocument()', function ( assert ) {\n\tassert.strictEqual( util.getDocument().length, 1 );\n} );\n\nQUnit.test( 'getWindow()', function ( assert ) {\n\tassert.strictEqual( util.getWindow().length, 1 );\n} );\n\nQUnit.test( 'parseHTML()', function ( assert ) {\n\tvar htmlFragment = util.parseHTML( '<p>element content</p>', document );\n\tassert.strictEqual( typeof htmlFragment === 'object', true );\n\tassert.strictEqual( htmlFragment[ 0 ].innerHTML, 'element content' );\n} );\n\nQUnit.test( 'isNumeric()', function ( assert ) {\n\tassert.strictEqual( util.isNumeric( 123 ), true );\n\tassert.strictEqual( util.isNumeric( '123' ), true );\n\tassert.strictEqual( util.isNumeric( 'The string 123 is true? I don\\'t like it.' ), false );\n\tassert.strictEqual( util.isNumeric( NaN ), false );\n} );\n\nQUnit.test( 'extend()', function ( assert ) {\n\tvar a = { a: 'apple' },\n\t\tb = { b: 'banana' };\n\tutil.extend( a, b );\n\tassert.strictEqual( JSON.stringify( a ), '{\"a\":\"apple\",\"b\":\"banana\"}' );\n} );\n\nQUnit.test( 'escapeHash()', function ( assert ) {\n\tassert.strictEqual( util.escapeHash( '#escape:...hash' ), '#escape\\\\:\\\\.\\\\.\\\\.hash' );\n} );\n\nQUnit.test( 'isModifiedEvent() - true', function ( assert ) {\n\tvar testEl = document.createElement( 'div' );\n\n\ttestEl.addEventListener( 'click', function ( ev ) {\n\t\tassert.strictEqual( util.isModifiedEvent( ev ), true );\n\t} );\n\n\ttestEl.dispatchEvent( new window.MouseEvent( 'click', { ctrlKey: true } ) );\n} );\n\nQUnit.test( 'isModifiedEvent() - false', function ( assert ) {\n\tvar testEl = document.createElement( 'div' );\n\n\ttestEl.addEventListener( 'click', function ( ev ) {\n\t\tassert.strictEqual( util.isModifiedEvent( ev ), false );\n\t} );\n\n\ttestEl.dispatchEvent( new window.MouseEvent( 'click' ) );\n} );\n\nQUnit.test( 'repeatEvent', function ( assert ) {\n\tvar proxy = new OO.EventEmitter(),\n\t\tsrc = new OO.EventEmitter(),\n\t\tsrcEventData = 'test data';\n\n\tutil.repeatEvent( src, proxy, 'test' );\n\n\tproxy.on( 'test', function ( data ) {\n\t\tassert.strictEqual(\n\t\t\tdata,\n\t\t\tsrcEventData,\n\t\t\t'proxy responds to source events correctly' );\n\t} );\n\tsrc.emit( 'test', srcEventData );\n} );\n","/* global $ */\nvar\n\t// feature dependencies\n\t// require OO or mw global\n\tWatchstar, CtaDrawer, toast, Icon, watchIcon, user, Page, toastSpy,\n\t// setup dependencies\n\tdom = require( '../../utils/dom' ),\n\tjQuery = require( '../../utils/jQuery' ),\n\tsinon = require( 'sinon' ),\n\tmediawiki = require( '../../utils/mw' ),\n\too = require( '../../utils/oo' ),\n\tutil = require( '../../../../src/mobile.startup/util' );\n\n/** @type {sinon.SinonSandbox} */ var sandbox; // eslint-disable-line one-var\n\nQUnit.module( 'MobileFrontend Watchstar.js', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\tmediawiki.setUp( sandbox, global );\n\t\too.setUp( sandbox, global );\n\n\t\t// requires OO global\n\t\tWatchstar = require( '../../../../src/mobile.startup/watchstar/Watchstar' );\n\t\tCtaDrawer = require( '../../../../src/mobile.startup/CtaDrawer' );\n\t\tIcon = require( '../../../../src/mobile.startup/Icon' );\n\t\tuser = mw.user;\n\t\tPage = require( '../../../../src/mobile.startup/Page' );\n\t\twatchIcon = new Icon( {\n\t\t\tname: 'watched'\n\t\t} );\n\t\t// require after stubbing\n\t\ttoast = require( '../../../../src/mobile.startup/toast' );\n\t\t// Avoid unnecessary mw.notify animations\n\t\tsandbox.stub( mw, 'notify', function () {} );\n\t\ttoastSpy = sandbox.spy( toast, 'show' );\n\t},\n\tafterEach: function () {\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( 'Anonymous user opens drawer', function ( assert ) {\n\tvar ctaDrawerSpy, $el;\n\n\tsandbox.stub( user, 'isAnon' ).returns( true );\n\tctaDrawerSpy = sandbox.stub( CtaDrawer.prototype, 'show' );\n\t$el = $( '<div>' );\n\n\t// eslint-disable-next-line no-new\n\tnew Watchstar( {\n\t\tapi: new mw.Api(),\n\t\tel: $el,\n\t\tpage: new Page( { title: 'Title' } )\n\t} );\n\t$el.trigger( 'click' );\n\n\t// position-fixed class may not have loaded and without it the toast is not visible so use\n\t// a spy rather than directly testing toast element visibility\n\tassert.ok( ctaDrawerSpy.called, 'We checked if the drawer was visible before displaying it' );\n} );\n\nQUnit.test( 'Logged in user watches article', function ( assert ) {\n\tvar w, $el, postWithTokenDeferred, apiSpy;\n\t// setting user as logged in\n\tsandbox.stub( user, 'isAnon', function () {\n\t\treturn false;\n\t} );\n\n\tw = new Watchstar( {\n\t\tapi: new mw.Api(),\n\t\tisWatched: false,\n\t\tpage: new Page( { title: 'Title' } )\n\t} );\n\t$el = w.$el;\n\tpostWithTokenDeferred = util.Deferred().resolve();\n\tapiSpy = sandbox.stub( w.gateway.api, 'postWithToken' ).returns( postWithTokenDeferred );\n\n\t$el.trigger( 'click' );\n\n\treturn postWithTokenDeferred.then( function () {\n\t\tassert.ok( apiSpy.calledWith( 'watch', {\n\t\t\taction: 'watch',\n\t\t\ttitles: [ 'Title' ]\n\t\t} ), 'The watch happened' );\n\t\tassert.strictEqual( $el.hasClass( watchIcon.getGlyphClassName() ),\n\t\t\ttrue, 'After successful watch has watched class' );\n\t\tassert.strictEqual( toastSpy.callCount, 1, 'A toast is shown' );\n\t} );\n} );\n\nQUnit.test( 'Logged in user unwatches article', function ( assert ) {\n\tvar w, $el, postWithTokenDeferred, apiSpy;\n\n\t// setting user as logged in\n\tsandbox.stub( user, 'isAnon', function () {\n\t\treturn false;\n\t} );\n\n\tw = new Watchstar( {\n\t\tapi: new mw.Api(),\n\t\tisWatched: true,\n\t\tpage: new Page( { title: 'Title' } )\n\t} );\n\t$el = w.$el;\n\tpostWithTokenDeferred = util.Deferred().resolve();\n\tapiSpy = sandbox.stub( w.gateway.api, 'postWithToken' ).returns( postWithTokenDeferred );\n\n\t$el.trigger( 'click' );\n\n\treturn postWithTokenDeferred.then( function () {\n\t\tassert.ok( apiSpy.calledWith( 'watch', {\n\t\t\taction: 'watch',\n\t\t\tunwatch: true,\n\t\t\ttitles: [ 'Title' ]\n\t\t} ), 'The watch happened' );\n\t\tassert.strictEqual( toastSpy.callCount, 1, 'A toast is shown' );\n\t} );\n} );\n","var\n\tWatchstarGateway = require( '../../../../src/mobile.startup/watchstar/WatchstarGateway' ),\n\t// setup dependencies\n\tdom = require( '../../utils/dom' ),\n\tjQuery = require( '../../utils/jQuery' ),\n\tsinon = require( 'sinon' ),\n\tmediawiki = require( '../../utils/mw' ),\n\tutil = require( '../../../../src/mobile.startup/util' ),\n\tGET_RESPONSE = {\n\t\tbatchcomplete: true,\n\t\tquery: {\n\t\t\tpages: [ {\n\t\t\t\tpageid: 123,\n\t\t\t\tns: 0,\n\t\t\t\ttitle: 'An unwatched page',\n\t\t\t\tcontentmodel: 'wikitext',\n\t\t\t\tpagelanguage: 'en',\n\t\t\t\tpagelanguagehtmlcode: 'en',\n\t\t\t\tpagelanguagedir: 'ltr',\n\t\t\t\ttouched: '2018-05-01T01:39:12Z',\n\t\t\t\tlastrevid: 10,\n\t\t\t\tlength: 3,\n\t\t\t\tnew: true,\n\t\t\t\twatched: false\n\t\t\t}, {\n\t\t\t\tpageid: 456,\n\t\t\t\tns: 0,\n\t\t\t\ttitle: 'A watched page',\n\t\t\t\tcontentmodel: 'wikitext',\n\t\t\t\tpagelanguage: 'en',\n\t\t\t\tpagelanguagehtmlcode: 'en',\n\t\t\t\tpagelanguagedir: 'ltr',\n\t\t\t\ttouched: '2018-05-01T01:43:31Z',\n\t\t\t\tlastrevid: 24,\n\t\t\t\tlength: 3,\n\t\t\t\tnew: true,\n\t\t\t\twatched: true\n\t\t\t} ]\n\t\t}\n\t},\n\tsandbox;\n\nQUnit.module( 'MobileFrontend: WatchstarGateway.js', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\tmediawiki.setUp( sandbox, global );\n\t},\n\tafterEach: function () {\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( 'getStatuses(nonempty)', function ( assert ) {\n\tvar\n\t\tsubject,\n\t\texpected,\n\t\tapi,\n\t\tmockAPI;\n\n\tapi = { get: function () {} };\n\tmockAPI = sandbox.mock( api );\n\n\tmockAPI\n\t\t.expects( 'get' )\n\t\t.withArgs( sandbox.match.has( 'pageids' ) )\n\t\t.once()\n\t\t.returns( util.Deferred().resolve( {\n\t\t\tbatchcomplete: true,\n\t\t\tquery: { pages: [ GET_RESPONSE.query.pages[0] ] }\n\t\t} ) );\n\tmockAPI\n\t\t.expects( 'get' )\n\t\t.withArgs( sandbox.match.has( 'titles' ) )\n\t\t.once()\n\t\t.returns( util.Deferred().resolve( {\n\t\t\tbatchcomplete: true,\n\t\t\tquery: { pages: [ GET_RESPONSE.query.pages[1] ] }\n\t\t} ) );\n\n\tsubject = new WatchstarGateway( api );\n\treturn subject.getStatuses(\n\t\t[ '123' ], [ 'A watched page' ]\n\t).then( function ( actual ) {\n\t\texpected = {\n\t\t\t'An unwatched page': false,\n\t\t\t'A watched page': true\n\t\t};\n\t\tassert.propEqual( actual, expected, 'The correct result is returned.' );\n\t\tmockAPI.verify();\n\t} );\n} );\n\nQUnit.test( 'getStatuses(empty)', function ( assert ) {\n\tvar\n\t\tsubject,\n\t\texpected,\n\t\tapi,\n\t\tmockAPI;\n\n\tapi = { get: function () {} };\n\tmockAPI = sandbox.mock( api )\n\t\t.expects( 'get' )\n\t\t// No HTTP requests are issued.\n\t\t.never();\n\n\tsubject = new WatchstarGateway( api );\n\treturn subject.getStatuses( [], [] ).then( function ( actual ) {\n\t\texpected = {};\n\t\tassert.propEqual( actual, expected, 'An empty result is returned.' );\n\t\tmockAPI.verify();\n\t} );\n} );\n\nQUnit.test( 'getStatusesByID(nonempty)', function ( assert ) {\n\tvar\n\t\tsubject,\n\t\texpected,\n\t\tapi,\n\t\tmockAPI;\n\n\tapi = { get: function () {} };\n\tmockAPI = sandbox.mock( api )\n\t\t.expects( 'get' )\n\t\t.once()\n\t\t// One HTTP request is issued.\n\t\t.returns( util.Deferred().resolve( GET_RESPONSE ) );\n\n\tsubject = new WatchstarGateway( api );\n\treturn subject.getStatusesByID( [ '123', 456 ] ).then( function ( actual ) {\n\t\texpected = {\n\t\t\t'An unwatched page': false,\n\t\t\t'A watched page': true\n\t\t};\n\t\tassert.propEqual( actual, expected, 'The correct result is returned.' );\n\t\tmockAPI.verify();\n\t} );\n} );\n\nQUnit.test( 'getStatusesByID(empty)', function ( assert ) {\n\tvar\n\t\tsubject,\n\t\texpected,\n\t\tapi,\n\t\tmockAPI;\n\n\tapi = { get: function () {} };\n\tmockAPI = sandbox.mock( api )\n\t\t.expects( 'get' )\n\t\t// No HTTP requests are issued.\n\t\t.never();\n\n\tsubject = new WatchstarGateway( api );\n\treturn subject.getStatusesByID( [] ).then( function ( actual ) {\n\t\texpected = {};\n\t\tassert.propEqual( actual, expected, 'An empty result is returned.' );\n\t\tmockAPI.verify();\n\t} );\n} );\n\nQUnit.test( 'getStatusesByTitle(nonempty)', function ( assert ) {\n\tvar\n\t\tsubject,\n\t\texpected,\n\t\tapi,\n\t\tmockAPI;\n\n\tapi = { get: function () {} };\n\tmockAPI = sandbox.mock( api )\n\t\t.expects( 'get' )\n\t\t.once()\n\t\t// One HTTP request is issued.\n\t\t.returns( util.Deferred().resolve( GET_RESPONSE ) );\n\n\tsubject = new WatchstarGateway( api );\n\treturn subject.getStatusesByTitle( [\n\t\t'An unwatched page', 'An unwatched page'\n\t] ).then( function ( actual ) {\n\t\texpected = {\n\t\t\t'An unwatched page': false,\n\t\t\t'A watched page': true\n\t\t};\n\t\tassert.propEqual( actual, expected, 'The correct result is returned.' );\n\t\tmockAPI.verify();\n\t} );\n} );\n\nQUnit.test( 'getStatusesByTitle(empty)', function ( assert ) {\n\tvar\n\t\tsubject,\n\t\texpected,\n\t\tapi,\n\t\tmockAPI;\n\n\tapi = { get: function () {} };\n\tmockAPI = sandbox.mock( api )\n\t\t.expects( 'get' )\n\t\t// No HTTP requests are issued.\n\t\t.never();\n\n\tsubject = new WatchstarGateway( api );\n\treturn subject.getStatusesByTitle( [] ).then( function ( actual ) {\n\t\texpected = {};\n\t\tassert.propEqual( actual, expected, 'An empty result is returned.' );\n\t\tmockAPI.verify();\n\t} );\n} );\n\nQUnit.test( '_unmarshalGetResponse(nonempty)', function ( assert ) {\n\tvar\n\t\tsubject,\n\t\tactual,\n\t\texpected;\n\n\tsubject = new WatchstarGateway( new mw.Api() );\n\tactual = subject._unmarshalGetResponse( GET_RESPONSE );\n\texpected = {\n\t\t'An unwatched page': false,\n\t\t'A watched page': true\n\t};\n\tassert.propEqual(\n\t\tactual,\n\t\texpected,\n\t\t'GET API:Info nonempty responses are unmarshalled correctly.'\n\t);\n} );\n\nQUnit.test( '_unmarshalGetResponse(empty)', function ( assert ) {\n\tvar\n\t\tsubject,\n\t\tactual,\n\t\texpected;\n\n\tsubject = new WatchstarGateway( new mw.Api() );\n\tactual = subject._unmarshalGetResponse( {} );\n\texpected = {};\n\tassert.propEqual(\n\t\tactual,\n\t\texpected,\n\t\t'GET API:Info empty responses are unmarshalled correctly.'\n\t);\n} );\n","var\n\tutil = require( '../../../../src/mobile.startup/util' ),\n\tdom = require( '../../utils/dom' ),\n\tjQuery = require( '../../utils/jQuery' ),\n\tsinon = require( 'sinon' ),\n\tmediawiki = require( '../../utils/mw' ),\n\too = require( '../../utils/oo' ),\n\tapiResp = {\n\t\tquery: {\n\t\t\tpages: [ {\n\t\t\t\tpageid: 30,\n\t\t\t\ttitle: 'Title 30',\n\t\t\t\twatched: true\n\t\t\t}, {\n\t\t\t\tpageid: 50,\n\t\t\t\ttitle: 'Title 50',\n\t\t\t\twatched: false\n\t\t\t} ]\n\t\t}\n\t},\n\tuser,\n\tIcon,\n\tWatchstarPageList,\n\twatchIconName,\n\tsandbox;\n\nQUnit.module( 'MobileFrontend mobile.startup/WatchstarPageList', {\n\tbeforeEach: function () {\n\n\t\tsandbox = sinon.sandbox.create();\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\tmediawiki.setUp( sandbox, global );\n\t\too.setUp( sandbox, global );\n\n\t\t// loaded after globals\n\t\tWatchstarPageList = require( '../../../../src/mobile.startup/watchstar/WatchstarPageList' );\n\t\tuser = mw.user;\n\t\tIcon = require( '../../../../src/mobile.startup/Icon' );\n\n\t\twatchIconName = new Icon( {\n\t\t\tname: 'watched'\n\t\t} ).getGlyphClassName();\n\t\tsandbox.stub( user, 'isAnon' ).returns( false );\n\t},\n\tafterEach: function () {\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( 'Watchlist status check if no ids', function ( assert ) {\n\tvar\n\t\tdone = assert.async(),\n\t\tmwApi = new mw.Api(),\n\t\tapiSpy = sandbox.stub( mwApi, 'get' ).returns( util.Deferred().resolve( apiResp ) ),\n\t\tpageList = new WatchstarPageList( {\n\t\t\tapi: mwApi,\n\t\t\tpages: [\n\t\t\t\t{ title: 'Title 0' },\n\t\t\t\t{ title: 'Title 1' }\n\t\t\t]\n\t\t} );\n\n\t// Wait for an internal API call to happen as a side-effect of construction.\n\twindow.setTimeout( function () {\n\t\tpageList.getPages( [], [] ).then( function () {\n\t\t\tassert.ok( apiSpy.calledWith( {\n\t\t\t\tformatversion: 2,\n\t\t\t\taction: 'query',\n\t\t\t\tprop: 'info',\n\t\t\t\tinprop: 'watched',\n\t\t\t\ttitles: [ 'Title 0', 'Title 1' ]\n\t\t\t} ), 'A request to API was made to retrieve the statuses' );\n\t\t\tassert.strictEqual( pageList.$el.find( '.watch-this-article' ).length, 2, '2 articles have watch stars' );\n\t\t\tdone();\n\t\t} );\n\t}, 0 );\n} );\n\nQUnit.test( 'Checks watchlist status once', function ( assert ) {\n\tvar\n\t\tdone = assert.async(),\n\t\tmwApi = new mw.Api(),\n\t\tapiSpy = sandbox.stub( mwApi, 'get' ).returns( util.Deferred().resolve( apiResp ) ),\n\t\tpl = new WatchstarPageList( {\n\t\t\tapi: mwApi,\n\t\t\tpages: [ {\n\t\t\t\tid: 30,\n\t\t\t\ttitle: 'Title 30'\n\t\t\t}, {\n\t\t\t\tid: 50,\n\t\t\t\ttitle: 'Title 50'\n\t\t\t} ]\n\t\t} );\n\n\t// Wait for an internal API call to happen as a side-effect of construction.\n\twindow.setTimeout( function () {\n\t\tpl.getPages( [ 30, 50 ], [] ).then( function () {\n\t\t\tassert.strictEqual( apiSpy.callCount, 2,\n\t\t\t\t'run callback twice (inside postRender and this call) - no caching occurs' );\n\t\t\tassert.ok( apiSpy.calledWith( {\n\t\t\t\tformatversion: 2,\n\t\t\t\taction: 'query',\n\t\t\t\tprop: 'info',\n\t\t\t\tinprop: 'watched',\n\t\t\t\tpageids: [ 30, 50 ]\n\t\t\t} ), 'A request to API was made to retrieve the statuses' );\n\t\t\tassert.strictEqual( pl.$el.find( '.watch-this-article' ).length, 2, '2 articles have watch stars' );\n\t\t\tassert.strictEqual( pl.$el.find( '.' + watchIconName ).length, 1, '1 article is marked as watched' );\n\t\t\tdone();\n\t\t} );\n\t}, 0 );\n} );\n","let\n\tAddTopicForm,\n\tsandbox;\nconst util = require( '../../../src/mobile.startup/util' ),\n\tjQuery = require( '../utils/jQuery' ),\n\tdom = require( '../utils/dom' ),\n\tmediaWiki = require( '../utils/mw' ),\n\too = require( '../utils/oo' ),\n\tsinon = require( 'sinon' );\n\nQUnit.module( 'MobileFrontend AddTopicForm', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\too.setUp( sandbox, global );\n\t\tmediaWiki.setUp( sandbox, global );\n\t\tAddTopicForm = require( '../../../src/mobile.talk.overlays/AddTopicForm' );\n\t},\n\tafterEach: function () {\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( 'makePanel()', function ( assert ) {\n\tconst text = 'Hello world',\n\t\tpanel = AddTopicForm.test.makePanel( util.parseHTML( '<span>' ).text( text ) );\n\n\tassert.strictEqual( panel.$el.hasClass( 'panel' ), true, 'A Panel is created' );\n\tassert.strictEqual( panel.$el.find( 'span' ).text(),\n\t\ttext, 'The panel has he element inside' );\n} );\n\nQUnit.test( 'AddTopicForm', function ( assert ) {\n\tconst spy = sandbox.spy(),\n\t\tformNoInputEvent = new AddTopicForm( {\n\t\t\tsubject: ' Subject',\n\t\t\tbody: 'Body',\n\t\t\tdisabled: false,\n\t\t\tlicenseMsg: 'MobileFrontend <strong>fun</strong> license'\n\t\t} ),\n\t\tform = new AddTopicForm( {\n\t\t\tsubject: ' Subject',\n\t\t\tbody: 'Body',\n\t\t\tdisabled: false,\n\t\t\tlicenseMsg: 'MobileFrontend <strong>fun</strong> license',\n\t\t\tonTextInput: function ( subject, body ) {\n\t\t\t\tspy( subject, body );\n\t\t\t}\n\t\t} );\n\n\t// form without an input\n\ttry {\n\t\tformNoInputEvent.$el.find( 'textarea' ).trigger( 'input' );\n\t\tassert.ok( true, 'If form has no onTextInput event handler does not execute' );\n\t} catch ( e ) {\n\t\tassert.ok( false, 'If form has no onTextInput no exception is meant to be thrown' );\n\t}\n\tassert.strictEqual( form.$el.find( 'input' ).val(), ' Subject', 'Subject input created' );\n\tassert.strictEqual( form.$el.find( 'textarea' ).val(), 'Body', 'textarea created' );\n\tassert.strictEqual( form.$el.find( 'p strong' ).text(), 'fun', 'licenseMsg accepts HTML' );\n\tassert.strictEqual( spy.calledOnce, false, 'Spy not called to begin with' );\n\tform.$el.find( 'textarea' ).trigger( 'input' );\n\tassert.strictEqual( spy.calledOnce, true, 'Spy got called after textarea input' );\n\tassert.propEqual( spy.args[0], [ 'Subject', 'Body' ],\n\t\t'Spy got called with expected (and trimmed arguments)' );\n\n} );\n","var\n\tTalkSectionAddOverlay,\n\tsandbox,\n\tutil = require( '../../../src/mobile.startup/util' ),\n\tjQuery = require( '../utils/jQuery' ),\n\tdom = require( '../utils/dom' ),\n\tmediaWiki = require( '../utils/mw' ),\n\too = require( '../utils/oo' ),\n\tsinon = require( 'sinon' );\n\nQUnit.module( 'MobileFrontend TalkSectionAddOverlay', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\too.setUp( sandbox, global );\n\t\tmediaWiki.setUp( sandbox, global );\n\n\t\tTalkSectionAddOverlay = require( '../../../src/mobile.talk.overlays/TalkSectionAddOverlay' );\n\t},\n\tafterEach: function () {\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( 'save()', function ( assert ) {\n\tvar overlay = new TalkSectionAddOverlay( {\n\t\tapi: {\n\t\t\tpostWithToken: sandbox.stub().returns(\n\t\t\t\tutil.Deferred().resolve()\n\t\t\t)\n\t\t},\n\t\ttitle: 'Talk:No exist'\n\t} );\n\t// set the content of the new discussion\n\toverlay.$el.find( 'input' ).val( 'Testtitle' );\n\toverlay.$el.find( 'textarea' ).val( 'Testcontent' );\n\t// Check the values\n\tassert.strictEqual( overlay.$el.find( 'input' ).val(), 'Testtitle', 'Testtitle set' );\n\tassert.strictEqual( overlay.$el.find( 'textarea' ).val(), 'Testcontent', 'Testcontent set' );\n\t// Test the save of the new dicsussion\n\treturn overlay.save().then( function ( status ) {\n\t\tassert.strictEqual( status, 'ok', 'The new discussion was saved' );\n\t\t// check, if the save was recognized\n\t\t// (so the overlay can hide without confirmation of the user)\n\t\tassert.strictEqual( overlay._saveHit, true, 'The save was recognized' );\n\t} );\n} );\n","var\n\tTalkSectionOverlay,\n\tsandbox,\n\tutil = require( '../../../src/mobile.startup/util' ),\n\tjQuery = require( '../utils/jQuery' ),\n\tdom = require( '../utils/dom' ),\n\tmediaWiki = require( '../utils/mw' ),\n\too = require( '../utils/oo' ),\n\tsinon = require( 'sinon' );\n\nQUnit.module( 'MobileFrontend TalkSectionOverlay.js - logged in', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\too.setUp( sandbox, global );\n\t\tmediaWiki.setUp( sandbox, global );\n\n\t\tTalkSectionOverlay = require( '../../../src/mobile.talk.overlays/TalkSectionOverlay' );\n\n\t\t// don't create toasts in test environment\n\t\tthis.toastStub = sandbox.stub( mw, 'notify' );\n\n\t\tsandbox.stub( mw.user, 'isAnon' ).returns( false );\n\t\tthis.renderFromApiSpy = sandbox.stub( TalkSectionOverlay.prototype, 'renderFromApi' );\n\t},\n\tafterEach: function () {\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( 'Load section from api only, if needed', function ( assert ) {\n\t// eslint-disable-next-line no-new\n\tnew TalkSectionOverlay( {\n\t\tapi: {},\n\t\tsection: 'Testtext'\n\t} );\n\n\tassert.strictEqual( this.renderFromApiSpy.callCount, 0, 'Section requested from api, if no section given.' );\n\n\t// eslint-disable-next-line no-new\n\tnew TalkSectionOverlay( {\n\t\tapi: {}\n\t} );\n\tassert.strictEqual( this.renderFromApiSpy.callCount, 1, 'No Api request, if section given' );\n} );\n\nQUnit.test( 'Check comment box for logged in users', function ( assert ) {\n\tvar overlay = new TalkSectionOverlay( {\n\t\tapi: {},\n\t\tsection: 'Test'\n\t} );\n\n\tassert.ok( overlay.$el.find( '.comment' ).length > 0, 'There is a visible comment box' );\n} );\n\nQUnit.test( 'Check error class on textarea', function ( assert ) {\n\tvar overlay;\n\n\toverlay = new TalkSectionOverlay( {\n\t\tapi: {},\n\t\tsection: 'Test'\n\t} );\n\n\t// add error class\n\toverlay.onSaveClick();\n\tassert.ok( overlay.$textarea.hasClass( 'error' ), 'Error class added when try to submit empty comment box.' );\n\toverlay.onFocusTextarea();\n\tassert.strictEqual( overlay.$textarea.hasClass( 'error' ), false, 'Error class removed after comment box get focus.' );\n} );\n\nQUnit.test( 'Check api request on save', function ( assert ) {\n\tvar\n\t\tdeferred = util.Deferred().resolve(),\n\t\tspy = sandbox.stub().returns( deferred ),\n\t\toverlay = new TalkSectionOverlay( {\n\t\t\tapi: {\n\t\t\t\tpostWithToken: spy\n\t\t\t},\n\t\t\ttitle: 'Talk:Test',\n\t\t\tid: 1,\n\t\t\tsection: 'Test'\n\t\t} );\n\n\toverlay.$textarea.val( 'Testcomment' );\n\toverlay.onSaveClick();\n\n\treturn deferred.then( function () {\n\t\tassert.ok( spy.calledWith( 'csrf', {\n\t\t\taction: 'edit',\n\t\t\ttitle: 'Talk:Test',\n\t\t\tsection: 1,\n\t\t\tappendtext: '\\n\\nTestcomment ~~~~',\n\t\t\tredirect: true\n\t\t} ), 'Save request passes!' );\n\t} );\n} );\n\nQUnit.module( 'MobileFrontend TalkSectionOverlay.js - anonymous (logged out)', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\too.setUp( sandbox, global );\n\t\tmediaWiki.setUp( sandbox, global );\n\n\t\tTalkSectionOverlay = require( '../../../src/mobile.talk.overlays/TalkSectionOverlay' );\n\n\t\tsandbox.stub( mw.user, 'isAnon' ).returns( false );\n\t},\n\tafterEach: function () {\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( 'Check comment box for logged out users', function ( assert ) {\n\tvar overlay = new TalkSectionOverlay( {\n\t\tapi: {},\n\t\tsection: 'Test'\n\t} );\n\n\tassert.ok( overlay.$el.find( '.comment' ).length > 0, 'There is a visible comment box' );\n} );\n","var autosign = require( '../../../src/mobile.talk.overlays/autosign' );\n\nQUnit.module( 'MobileFrontend autosign.js' );\n\nQUnit.test( '#autosign', function ( assert ) {\n\t[\n\t\t// Forgot to sign\n\t\t[ 'foo', 'foo ~~~~' ],\n\t\t// 3 tildes signing (no date)\n\t\t[ 'foo ~~~', 'foo ~~~' ],\n\t\t// 5 tildes (no name)\n\t\t[ 'foo ~~~~~', 'foo ~~~~~' ],\n\t\t// No double signing\n\t\t[ 'foo ~~~~', 'foo ~~~~' ],\n\t\t// Unconventional signing1\n\t\t[ 'foo ~~~~ yolo', 'foo ~~~~ yolo' ],\n\t\t// Unconventional signing 2\n\t\t[ '~~~~ yolo', '~~~~ yolo' ]\n\t].forEach( function ( testCase ) {\n\t\tassert.strictEqual( autosign( testCase[0] ), testCase[1], 'Autosigning works as expected' );\n\t} );\n} );\n","let makeAddTopicForm, sandbox;\nconst jQuery = require( '../utils/jQuery' ),\n\tdom = require( '../utils/dom' ),\n\tmediaWiki = require( '../utils/mw' ),\n\too = require( '../utils/oo' ),\n\tsinon = require( 'sinon' );\n\nQUnit.module( 'MobileFrontend makeAddTopicForm', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\too.setUp( sandbox, global );\n\t\tmediaWiki.setUp( sandbox, global );\n\t\tmakeAddTopicForm = require( '../../../src/mobile.talk.overlays/makeAddTopicForm' );\n\t},\n\tafterEach: function () {\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( 'makeAddTopicForm', function ( assert ) {\n\tconst spy = sandbox.spy(),\n\t\tformNoHandler = makeAddTopicForm( {\n\t\t\tlicenseMsg: 'foo',\n\t\t\tdisabled: false,\n\t\t\tsubject: 'sub',\n\t\t\tbody: 'body'\n\t\t} ),\n\t\tform = makeAddTopicForm( {\n\t\t\tlicenseMsg: 'foo',\n\t\t\tdisabled: false,\n\t\t\tsubject: 'sub',\n\t\t\tbody: 'body',\n\t\t\tonTextInput: function ( _, val ) {\n\t\t\t\tspy( val );\n\t\t\t}\n\t\t} );\n\tassert.strictEqual( formNoHandler.$el.hasClass( 'add-topic-form' ), true,\n\t\t'The onTextInput parameter is optional' );\n\tformNoHandler.$el.find( 'textarea' ).trigger( 'input' );\n\tform.$el.find( 'textarea' ).trigger( 'input' );\n\tform.$el.find( 'textarea' ).val( '' );\n\tform.$el.find( 'textarea' ).trigger( 'input' );\n\tassert.strictEqual( form.$el.hasClass( 'add-topic-form' ), true,\n\t\t'Form has the expected class name' );\n\tassert.strictEqual( spy.args[0][0], 'body ~~~~',\n\t\t'Check onTextInput is executed and signed when callback is run.' );\n\tassert.strictEqual( spy.args[1][0], '',\n\t\t'Check onTextInput does not autosign if body empty.' );\n} );\n","var talkBoard, Section, sandbox,\n\tjQuery = require( '../utils/jQuery' ),\n\tdom = require( '../utils/dom' ),\n\tmediaWiki = require( '../utils/mw' ),\n\too = require( '../utils/oo' ),\n\tsinon = require( 'sinon' );\n\nQUnit.module( 'MobileFrontend mobile.talk.overlays/talkBoard', {\n\tbeforeEach: function () {\n\t\tsandbox = sinon.sandbox.create();\n\t\tdom.setUp( sandbox, global );\n\t\tjQuery.setUp( sandbox, global );\n\t\too.setUp( sandbox, global );\n\t\tmediaWiki.setUp( sandbox, global );\n\n\t\tsandbox.stub( mw, 'msg' )\n\t\t\t.withArgs( 'mobile-frontend-talk-explained' ).returns( 'things' )\n\t\t\t.withArgs( 'mobile-frontend-talk-explained-empty' ).returns( 'empty' );\n\n\t\ttalkBoard = require( '../../../src/mobile.talk.overlays/talkBoard' );\n\t\tSection = require( '../../../src/mobile.startup/Section' );\n\t},\n\tafterEach: function () {\n\t\tjQuery.tearDown();\n\t\tsandbox.restore();\n\t}\n} );\n\nQUnit.test( 'no sections', function ( assert ) {\n\tvar board = talkBoard( [] );\n\tassert.strictEqual( board.$el.find( '.content-header' ).text().trim(), 'empty' );\n\tassert.strictEqual( board.$el.find( 'ul' ).children().length, 0, 'no topics' );\n} );\n\nQUnit.test( 'sections', function ( assert ) {\n\tvar board = talkBoard( [\n\t\tnew Section( {\n\t\t\tline: '1',\n\t\t\tid: '2'\n\t\t} )\n\t] );\n\tassert.strictEqual( board.$el.find( '.content-header' ).text().trim(), 'things' );\n\tassert.strictEqual( board.$el.find( 'ul' ).children().length, 1, '1 topic' );\n} );\n","module.exports = {\n\tgetPageHeadings: {\n\t\tinput: {\n\t\t\tmobileview: {\n\t\t\t\tid: -1,\n\t\t\t\tdisplaytitle: 'Test',\n\t\t\t\trevId: 42,\n\t\t\t\tlastmodifiedby: {\n\t\t\t\t\tname: 'bob',\n\t\t\t\t\tgender: 'unknown'\n\t\t\t\t},\n\t\t\t\tprotection: [],\n\t\t\t\tlastmodified: '2013-10-28T18:49:56Z',\n\t\t\t\tlanguagecount: 10,\n\t\t\t\tsections: [\n\t\t\t\t\t{\n\t\t\t\t\t\tid: 0,\n\t\t\t\t\t\ttext: ''\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tlevel: '1',\n\t\t\t\t\t\tline: '1',\n\t\t\t\t\t\tanchor: '1',\n\t\t\t\t\t\tid: 1,\n\t\t\t\t\t\ttext: '<p>Text of 1\\n</p>'\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tlevel: '2',\n\t\t\t\t\t\tline: '<i>1.1</i>',\n\t\t\t\t\t\tanchor: '1.1',\n\t\t\t\t\t\tid: 2,\n\t\t\t\t\t\ttext: '<p>Text of 1.1\\n</p>'\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tlevel: '1',\n\t\t\t\t\t\tline: '2',\n\t\t\t\t\t\tanchor: '2',\n\t\t\t\t\t\tid: 3,\n\t\t\t\t\t\ttext: '<p>Text of 2\\n</p>'\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tlevel: '2',\n\t\t\t\t\t\tline: '2.1',\n\t\t\t\t\t\tanchor: '2.1',\n\t\t\t\t\t\tid: 4,\n\t\t\t\t\t\ttext: '<p>Text of 2.1\\n</p>'\n\t\t\t\t\t} ]\n\t\t\t}\n\t\t},\n\t\toutput: {\n\t\t\thistoryUrl: 'Test:History',\n\t\t\tlastModifiedUserName: 'bob',\n\t\t\tlastModifiedUserGender: 'unknown',\n\t\t\tlastModifiedTimestamp: 1382986196,\n\t\t\ttitle: 'Test',\n\t\t\trevId: 42,\n\t\t\tdisplayTitle: 'Test',\n\t\t\tid: -1,\n\t\t\tprotection: {\n\t\t\t\tedit: [ '*' ]\n\t\t\t},\n\t\t\tisMainPage: false,\n\t\t\tlanguageCount: 10,\n\t\t\thasVariants: false,\n\t\t\tlead: '',\n\t\t\tsections: [\n\t\t\t\t{\n\t\t\t\t\tlevel: '1',\n\t\t\t\t\tline: '1',\n\t\t\t\t\tanchor: '1',\n\t\t\t\t\tid: 1,\n\t\t\t\t\ttext: '<p>Text of 1\\n</p><h2 id=\"1.1\"><i>1.1</i></h2>\\n<p>Text of 1.1\\n</p>\\n',\n\t\t\t\t\tsubsections: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tlevel: '2',\n\t\t\t\t\t\t\tline: '<i>1.1</i>',\n\t\t\t\t\t\t\tanchor: '1.1',\n\t\t\t\t\t\t\tid: 2,\n\t\t\t\t\t\t\ttext: '<p>Text of 1.1\\n</p>',\n\t\t\t\t\t\t\tsubsections: []\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlevel: '1',\n\t\t\t\t\tline: '2',\n\t\t\t\t\tanchor: '2',\n\t\t\t\t\tid: 3,\n\t\t\t\t\ttext: '<p>Text of 2\\n</p><h2 id=\"2.1\">2.1</h2>\\n<p>Text of 2.1\\n</p>\\n',\n\t\t\t\t\tsubsections: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tlevel: '2',\n\t\t\t\t\t\t\tline: '2.1',\n\t\t\t\t\t\t\tanchor: '2.1',\n\t\t\t\t\t\t\tid: 4,\n\t\t\t\t\t\t\ttext: '<p>Text of 2.1\\n</p>',\n\t\t\t\t\t\t\tsubsections: []\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t},\n\tgetPage: {\n\t\tinput: {\n\t\t\tmobileview: {\n\t\t\t\tid: -1,\n\t\t\t\tprotection: {\n\t\t\t\t\tedit: [ 'sysop' ]\n\t\t\t\t},\n\t\t\t\tlastmodifiedby: {\n\t\t\t\t\tname: 'Melissa',\n\t\t\t\t\tgender: 'female'\n\t\t\t\t},\n\t\t\t\trevId: 42,\n\t\t\t\tdisplaytitle: 'Test',\n\t\t\t\tlastmodified: '2013-10-28T18:49:56Z',\n\t\t\t\tlanguagecount: 10,\n\t\t\t\tsections: [\n\t\t\t\t\t{\n\t\t\t\t\t\tid: 0,\n\t\t\t\t\t\ttext: 'lead content'\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tlevel: '2',\n\t\t\t\t\t\tline: 'Aaa section',\n\t\t\t\t\t\tanchor: 'Aaa_section',\n\t\t\t\t\t\tid: 1,\n\t\t\t\t\t\ttext: 'aaa content'\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tlevel: '3',\n\t\t\t\t\t\tline: 'Subaaa section',\n\t\t\t\t\t\tanchor: 'Subaaa_section',\n\t\t\t\t\t\tid: 2,\n\t\t\t\t\t\ttext: 'subaaa content'\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tlevel: '2',\n\t\t\t\t\t\tline: 'Bbb section',\n\t\t\t\t\t\tanchor: 'Bbb_section',\n\t\t\t\t\t\tid: 3,\n\t\t\t\t\t\ttext: 'bbb content'\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tlevel: '2',\n\t\t\t\t\t\tline: 'References',\n\t\t\t\t\t\treferences: '',\n\t\t\t\t\t\tanchor: 'References',\n\t\t\t\t\t\tid: 4,\n\t\t\t\t\t\ttext: 'references'\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\toutput: {\n\t\t\thistoryUrl: 'Test:History',\n\t\t\tlastModifiedUserName: 'Melissa',\n\t\t\tlastModifiedUserGender: 'female',\n\t\t\tlastModifiedTimestamp: 1382986196,\n\t\t\tprotection: {\n\t\t\t\tedit: [ 'sysop' ]\n\t\t\t},\n\t\t\ttitle: 'Test',\n\t\t\tdisplayTitle: 'Test',\n\t\t\tid: -1,\n\t\t\tisMainPage: false,\n\t\t\trevId: 42,\n\t\t\tlanguageCount: 10,\n\t\t\thasVariants: false,\n\t\t\tlead: 'lead content',\n\t\t\tsections: [\n\t\t\t\t{\n\t\t\t\t\tlevel: '2',\n\t\t\t\t\tline: 'Aaa section',\n\t\t\t\t\tanchor: 'Aaa_section',\n\t\t\t\t\tid: 1,\n\t\t\t\t\ttext: 'aaa content<h3 id=\"Subaaa_section\">Subaaa section</h3>\\nsubaaa content\\n',\n\t\t\t\t\tsubsections: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tlevel: '3',\n\t\t\t\t\t\t\tline: 'Subaaa section',\n\t\t\t\t\t\t\tanchor: 'Subaaa_section',\n\t\t\t\t\t\t\tid: 2,\n\t\t\t\t\t\t\ttext: 'subaaa content',\n\t\t\t\t\t\t\tsubsections: []\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlevel: '2',\n\t\t\t\t\tline: 'Bbb section',\n\t\t\t\t\tanchor: 'Bbb_section',\n\t\t\t\t\tid: 3,\n\t\t\t\t\ttext: 'bbb content',\n\t\t\t\t\tsubsections: []\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlevel: '2',\n\t\t\t\t\tline: 'References',\n\t\t\t\t\treferences: '',\n\t\t\t\t\tanchor: 'References',\n\t\t\t\t\tid: 4,\n\t\t\t\t\ttext: 'references',\n\t\t\t\t\tsubsections: []\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t},\n\tgetPageLanguagesResponse: {\n\t\tinput: {\n\t\t\tquery: {\n\t\t\t\tpages: [\n\t\t\t\t\t{\n\t\t\t\t\t\tpageid: 94,\n\t\t\t\t\t\tns: 0,\n\t\t\t\t\t\ttitle: 'San Francisco',\n\t\t\t\t\t\tlanglinks: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tlang: 'es',\n\t\t\t\t\t\t\t\turl: 'http://es.wikipedia.org/wiki/San_Francisco_(California)',\n\t\t\t\t\t\t\t\ttitle: 'San Francisco (California)',\n\t\t\t\t\t\t\t\tautonym: 'espa\\u00f1ol'\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tlang: 'pl',\n\t\t\t\t\t\t\t\turl: 'http://pl.wikipedia.org/wiki/San_Francisco',\n\t\t\t\t\t\t\t\ttitle: 'San Francisco',\n\t\t\t\t\t\t\t\tautonym: 'polski'\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tlang: 'sr',\n\t\t\t\t\t\t\t\turl: 'http://sr.wikipedia.org/wiki/%D0%A1%D0%B0%D0%BD_%D0%A4%D1%80%D0%B0%D0%BD%D1%86%D0%B8%D1%81%D0%BA%D0%BE',\n\t\t\t\t\t\t\t\ttitle: '\\u0421\\u0430\\u043d \\u0424\\u0440\\u0430\\u043d\\u0446\\u0438\\u0441\\u043a\\u043e',\n\t\t\t\t\t\t\t\tautonym: '\\u0441\\u0440\\u043f\\u0441\\u043a\\u0438 / srpski'\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t]\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\tgeneral: {\n\t\t\t\t\tvariants: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcode: 'sr',\n\t\t\t\t\t\t\tname: 'sr'\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcode: 'sr-ec',\n\t\t\t\t\t\t\tname: '\\u040b\\u0438\\u0440\\u0438\\u043b\\u0438\\u0446\\u0430'\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcode: 'sr-el',\n\t\t\t\t\t\t\tname: 'Latinica'\n\t\t\t\t\t\t}\n\t\t\t\t\t],\n\t\t\t\t\tvariantarticlepath: '/$2/$1'\n\t\t\t\t},\n\t\t\t\tlanguages: [\n\t\t\t\t\t{\n\t\t\t\t\t\tcode: 'sr',\n\t\t\t\t\t\tname: 'српски / srpski'\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tcode: 'sr-ec',\n\t\t\t\t\t\tname: 'српски (ћирилица)'\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tcode: 'sr-el',\n\t\t\t\t\t\tname: 'srpski (latinica)‎'\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tcode: 'es',\n\t\t\t\t\t\tname: 'español'\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tcode: 'pl',\n\t\t\t\t\t\tname: 'polski'\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t},\n\t\t\tlimits: {\n\t\t\t\tlanglinks: 500\n\t\t\t}\n\t\t},\n\t\toutput: {\n\t\t\tlanguages: [\n\t\t\t\t{\n\t\t\t\t\tlang: 'es',\n\t\t\t\t\turl: 'http://es.wikipedia.org/wiki/San_Francisco_(California)',\n\t\t\t\t\ttitle: 'San Francisco (California)',\n\t\t\t\t\tautonym: 'espa\\u00f1ol'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlang: 'pl',\n\t\t\t\t\turl: 'http://pl.wikipedia.org/wiki/San_Francisco',\n\t\t\t\t\ttitle: 'San Francisco',\n\t\t\t\t\tautonym: 'polski'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlang: 'sr',\n\t\t\t\t\turl: 'http://sr.wikipedia.org/wiki/%D0%A1%D0%B0%D0%BD_%D0%A4%D1%80%D0%B0%D0%BD%D1%86%D0%B8%D1%81%D0%BA%D0%BE',\n\t\t\t\t\ttitle: '\\u0421\\u0430\\u043d \\u0424\\u0440\\u0430\\u043d\\u0446\\u0438\\u0441\\u043a\\u043e',\n\t\t\t\t\tautonym: '\\u0441\\u0440\\u043f\\u0441\\u043a\\u0438 / srpski'\n\t\t\t\t}\n\t\t\t],\n\t\t\tvariants: [\n\t\t\t\t{\n\t\t\t\t\tlang: 'sr',\n\t\t\t\t\tautonym: 'sr',\n\t\t\t\t\turl: '/sr/Test'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlang: 'sr-ec',\n\t\t\t\t\tautonym: '\\u040b\\u0438\\u0440\\u0438\\u043b\\u0438\\u0446\\u0430',\n\t\t\t\t\turl: '/sr-ec/Test'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlang: 'sr-el',\n\t\t\t\t\tautonym: 'Latinica',\n\t\t\t\t\turl: '/sr-el/Test'\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t},\n\tgetPageLanguagesCall: {\n\t\toutput: {\n\t\t\taction: 'query',\n\t\t\tmeta: 'siteinfo',\n\t\t\tsiprop: 'general',\n\t\t\tprop: 'langlinks',\n\t\t\tllprop: 'url|autonym|langname',\n\t\t\tllinlanguagecode: 'fr',\n\t\t\tlllimit: 'max',\n\t\t\ttitles: 'Title',\n\t\t\tformatversion: 2\n\t\t}\n\t},\n\tgetAPIResponseFromHTML: {\n\t\tinput: [\n\t\t\t{\n\t\t\t\tline: 'A1',\n\t\t\t\tlevel: '1',\n\t\t\t\tanchor: '1.0',\n\t\t\t\ttext: ''\n\t\t\t},\n\t\t\t{\n\t\t\t\tline: 'A2.1',\n\t\t\t\tlevel: '2',\n\t\t\t\tanchor: '',\n\t\t\t\ttext: ''\n\t\t\t},\n\t\t\t{\n\t\t\t\tline: 'A2.2',\n\t\t\t\tlevel: '2',\n\t\t\t\tanchor: '',\n\t\t\t\ttext: ''\n\t\t\t},\n\t\t\t{\n\t\t\t\tline: 'A2',\n\t\t\t\tlevel: '1',\n\t\t\t\tanchor: '',\n\t\t\t\ttext: ''\n\t\t\t},\n\t\t\t{\n\t\t\t\tline: 'A2.1',\n\t\t\t\tlevel: '2',\n\t\t\t\tanchor: '',\n\t\t\t\ttext: ''\n\t\t\t}\n\t\t]\n\t}\n\n};\n","/* eslint-env es6 */\nvar page, page2, skinPage, referencesPage, lazyLoadedReferencesPage;\n\n/**\n * Important..\n * Even though this page supports ES6, it is still compiled to ES5\n * friendly JavaScript.\n * It is thus imperative you do not use substitution in these templates\n * or any other ES6 functions.\n * It is expected to run in Special:JavaScript/qunit/test.\n * A linter will bark at you if you break this.\n */\n\npage = `<div>\n\t<h1><span class=\"mw-headline\" id=\"1.0\">A1</span></h1>\n\t<h2><span class=\"mw-headline\">A2.1</span></h2>\n\t<h2><span class=\"mw-headline\">A2.2</span></h2>\n\t<h1><span class=\"mw-headline\">A2</span></h1>\n\t<h2><span class=\"mw-headline\">A2.1</span><span>[<a href=\"#\">edit</a>]</span></h2>\n\t<h1>Not to be shown in the TOC<span class=\"placeholder\"></span></h1>\n</div>`;\n\npage2 = `<div>\n<h2><span class=\"mw-headline\" id=\"1.0\">A1</span></h2>\n<h3><span class=\"mw-headline\">A2.1</span></h3>\n<h2><span class=\"mw-headline\">A2.2</span></h2>\n<h1><span class=\"mw-headline\">A2</span></h1>\n<h2><span class=\"mw-headline\">A2.1</span></h2>\n</div>`;\n\nskinPage = `<div id=\"mw-content-text\">\n\t<h2 class=\"section-heading collapsible-heading open-block\">\n\t\t<span class=\"mw-headline\" id=\"Notes_and_references\">Notes and references</span>\n\t</h2>\n\t<div class=\"mf-section-2 collapsible-block open-block\" data-is-reference-section=\"1\">\n\t\t<p>Text</p>\n\t\t<a class=\"mf-lazy-references-placeholder\"></a>\n\t\t<h3><span class=\"mw-headline\" id=\"Notes\">Notes</span></h3>\n\t\t<a class=\"mf-lazy-references-placeholder\"></a>\n\t\t<h4 class=\"in-block\"><span class=\"mw-headline\" id=\"Refs\">Refs</span></h4>\n\t\t<a class=\"mf-lazy-references-placeholder\"></a>\n\t\t<p>no forget</p>\n\t\t<h5 class=\"in-block\"><span class=\"mw-headline\" id=\"More_refs\">More refs</span></h5>\n\t\t<p>1</p>\n\t\t<a class=\"mf-lazy-references-placeholder\"></a>\n\t\t<p>2</p>\n\t\t<a class=\"mf-lazy-references-placeholder\"></a>\n\t\t<p>3</p>\n\t</div>\n</div>`;\n\nreferencesPage = `<div id=\"mfe-test-references\">\n<sup id=\"cite_ref-1\" class=\"reference\">\n\t<a href=\"#cite_note-1\">[1]</a>\n</sup>\n<p>\n\tsup with encoded href attribute\n\t<sup id=\"cite_ref-Obama_1995,_2004,_pp._9–10_11-0\" class=\"reference\">\n\t\t<a href=\"#cite_note-Obama_1995,_2004,_pp._9%E2%80%9310-11\">[11]</a>\n\t</sup>\n</p>\n<ol class=\"references\">\n\t<li id=\"cite_note-1\">\n\t\t<span class=\"mw-cite-backlink\">\n\t\t\t<a href=\"#cite_ref-1\">↑</a>\n\t\t</span> <span class=\"reference-text\">hello</span>\n\t</li>\n\t<li id=\"cite_note-Obama_1995,_2004,_pp._9–10-11\">\n\t\t<span class=\"mw-cite-backlink\">\n\t\t\t<a href=\"#cite_ref-1\">↑</a>\n\t\t</span> <span class=\"reference-text\">found</span>\n\t</li>\n</ol>\n</div>`;\n\nlazyLoadedReferencesPage = `<div>\n<h2><span class=\"mw-headline\" id=\"1.0\">A1</span></h1>\n<div>text</div>\n<h2>references</h2>\n<div>\n\t<a class=\"mf-lazy-references-placeholder\">View citations</a>\n</div>\n</div>`;\n\nmodule.exports = {\n\tlazyLoadedReferencesPage: lazyLoadedReferencesPage,\n\treferencesPage: referencesPage,\n\tskinPage: skinPage,\n\tpage: page,\n\tpage2: page2\n};\n","var\n\theadless = typeof window !== 'object',\n\tjsdom = headless && require( 'jsdom' );\n\nmodule.exports = {\n\t/**\n\t * @param {sinon.SinonSandbox} sandbox\n\t * @param {NodeJS.Global} global\n\t * @return {void}\n\t */\n\tsetUp: function ( sandbox, global ) {\n\t\tif ( headless ) {\n\t\t\tglobal.window = global.window || undefined;\n\t\t\tglobal.document = global.document || undefined;\n\t\t\tsandbox.stub( global, 'window', new jsdom.JSDOM().window );\n\t\t\tsandbox.stub( global, 'document', window.document );\n\t\t\tglobal.Image = global.window.Image;\n\t\t\tglobal.Event = global.window.Event;\n\t\t}\n\t}\n};\n","var headless = typeof window !== 'object';\n\nmodule.exports = {\n\t/**\n\t * @param {sinon.SinonSandbox} sandbox\n\t * @param {NodeJS.Global} global\n\t * @return {void}\n\t */\n\tsetUp: function ( sandbox, global ) {\n\t\tif ( headless ) {\n\t\t\tglobal.$ = global.$ || undefined;\n\t\t\tsandbox.stub( global, '$', require( 'jquery' ) );\n\t\t}\n\t},\n\ttearDown: function () {\n\t\tif ( headless ) {\n\t\t\t// prevent jQuery from caching the global window object.\n\t\t\tdelete require.cache[require.resolve( 'jquery' )];\n\t\t}\n\t}\n};\n","var\n\theadless = typeof window !== 'object',\n\tnewMockMediaWiki = require( './mockMediaWiki' );\n\nmodule.exports = {\n\t/**\n\t * @param {sinon.SinonSandbox} sandbox\n\t * @param {NodeJS.Global} global\n\t * @return {void}\n\t */\n\tsetUp: function ( sandbox, global ) {\n\t\tif ( headless ) {\n\t\t\tglobal.mw = global.mw || undefined;\n\t\t\tsandbox.stub( global, 'mw', newMockMediaWiki() );\n\t\t}\n\t}\n};\n","var headless = typeof window !== 'object';\n\nmodule.exports = {\n\t/**\n\t * @param {sinon.SinonSandbox} sandbox\n\t * @param {NodeJS.Global} global\n\t * @return {void}\n\t */\n\tsetUp: function ( sandbox, global ) {\n\t\tvar OO;\n\t\tif ( headless ) {\n\t\t\tOO = require( 'oojs' );\n\t\t\tOO.ui = {\n\t\t\t\tElement: {\n\t\t\t\t\tstatic: {\n\t\t\t\t\t\tgetClosestScrollableContainer: function () {}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tTool: function () {}\n\t\t\t};\n\t\t\tglobal.OO = global.OO || undefined;\n\t\t\tsandbox.stub( global, 'OO', OO );\n\t\t}\n\t}\n};\n","(function() { module.exports = this[\"jquery\"]; }());","(function() { module.exports = this[\"jsdom\"]; }());","(function() { module.exports = this[\"oojs\"]; }());","(function() { module.exports = this[\"sinon\"]; }());"],"sourceRoot":""}