mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/Popups
synced 2024-12-22 03:52:52 +00:00
3ec185cb01
Modified necessary files to increase size of popup from 300px to 320px Bug: T173434 Change-Id: I47bbe9defe961008163551d5be4fc7b1ca08d0d1
1 line
300 KiB
JSON
1 line
300 KiB
JSON
{"version":3,"sources":["/w/extensions/Popups/index.js","/w/extensions/Popups/webpack/bootstrap c9b1d11267645803e45f","/w/extensions/Popups/./~/redux-thunk/dist/redux-thunk.min.js","/w/extensions/Popups/./~/redux/dist/redux.min.js","/w/extensions/Popups/./src/actionTypes.js","/w/extensions/Popups/./src/actions.js","/w/extensions/Popups/./src/changeListener.js","/w/extensions/Popups/./src/changeListeners/eventLogging.js","/w/extensions/Popups/./src/changeListeners/footerLink.js","/w/extensions/Popups/./src/changeListeners/index.js","/w/extensions/Popups/./src/changeListeners/linkTitle.js","/w/extensions/Popups/./src/changeListeners/render.js","/w/extensions/Popups/./src/changeListeners/settings.js","/w/extensions/Popups/./src/changeListeners/statsv.js","/w/extensions/Popups/./src/changeListeners/syncUserSettings.js","/w/extensions/Popups/./src/constants.js","/w/extensions/Popups/./src/counts.js","/w/extensions/Popups/./src/experiments.js","/w/extensions/Popups/./src/formatter.js","/w/extensions/Popups/./src/gateway/index.js","/w/extensions/Popups/./src/gateway/mediawiki.js","/w/extensions/Popups/./src/gateway/rest.js","/w/extensions/Popups/./src/gateway/restFormatters.js","/w/extensions/Popups/./src/getUserBucket.js","/w/extensions/Popups/./src/index.js","/w/extensions/Popups/./src/instrumentation/eventLogging.js","/w/extensions/Popups/./src/instrumentation/statsv.js","/w/extensions/Popups/./src/integrations/mwpopups.js","/w/extensions/Popups/./src/isEnabled.js","/w/extensions/Popups/./src/preview/model.js","/w/extensions/Popups/./src/previewBehavior.js","/w/extensions/Popups/./src/reducers/eventLogging.js","/w/extensions/Popups/./src/reducers/index.js","/w/extensions/Popups/./src/reducers/nextState.js","/w/extensions/Popups/./src/reducers/preview.js","/w/extensions/Popups/./src/reducers/settings.js","/w/extensions/Popups/./src/reducers/statsv.js","/w/extensions/Popups/./src/title.js","/w/extensions/Popups/./src/ui/renderer.js","/w/extensions/Popups/./src/ui/settingsDialog.js","/w/extensions/Popups/./src/userSettings.js","/w/extensions/Popups/./src/wait.js"],"names":["modules","__webpack_require__","moduleId","installedModules","exports","module","i","l","call","m","c","value","d","name","getter","o","Object","defineProperty","configurable","enumerable","get","n","__esModule","object","property","prototype","hasOwnProperty","p","s","./node_modules/redux-thunk/dist/redux-thunk.min.js","t","e","this","r","id","loaded","dispatch","getState","withExtraArgument","default","./node_modules/redux/dist/redux.min.js","compose","applyMiddleware","bindActionCreators","combineReducers","createStore","u","a","f","arguments","length","Array","slice","reduceRight","apply","b","h","v","Error","push","indexOf","splice","type","y","INIT","subscribe","next","TypeError","unsubscribe","replaceReducer","ActionTypes","console","error","constructor","Function","toString","map","assign","keys","forEach","Math","random","substring","split","join","getPrototypeOf","window","Symbol","observable","./src/actionTypes.js","__webpack_exports__","BOOT","LINK_DWELL","ABANDON_START","ABANDON_END","LINK_CLICK","FETCH_START","FETCH_END","FETCH_COMPLETE","FETCH_FAILED","PREVIEW_DWELL","PREVIEW_SHOW","PREVIEW_CLICK","SETTINGS_SHOW","SETTINGS_HIDE","SETTINGS_CHANGE","EVENT_LOGGED","STATSV_LOGGED","./src/actions.js","timedAction","baseAction","timestamp","mw","now","boot","isEnabled","user","userSettings","generateToken","config","editCount","previewCount","getPreviewCount","__WEBPACK_IMPORTED_MODULE_0__actionTypes__","isNavPopupsEnabled","sessionToken","sessionId","pageToken","page","title","namespaceID","isAnon","fetch","gateway","el","token","titleText","getPrefixedDb","namespace","request","getPageSummary","then","result","fail","$","when","__WEBPACK_IMPORTED_MODULE_1__wait__","FETCH_COMPLETE_TARGET_DELAY","FETCH_START_DELAY","linkDwell","event","isNewInteraction","preview","activeToken","action","enabled","abandon","ABANDON_END_DELAY","linkClick","previewDwell","previewShow","showSettings","hideSettings","saveSettings","wasEnabled","eventLogged","statsvLogged","jQuery","mediaWiki","./src/changeListener.js","registerChangeListener","store","callback","state","prevState","./src/changeListeners/eventLogging.js","eventLogging","boundActions","eventLoggingTracker","_","extend","baseData","./src/changeListeners/footerLink.js","createFooterLink","$footer","$link","append","attr","text","message","hide","parent","footerLink","$footerLink","undefined","click","preventDefault","settings","shouldShowFooterLink","show","./src/changeListeners/index.js","__WEBPACK_IMPORTED_MODULE_0__footerLink__","__WEBPACK_IMPORTED_MODULE_1__eventLogging__","__WEBPACK_IMPORTED_MODULE_2__linkTitle__","__WEBPACK_IMPORTED_MODULE_3__render__","__WEBPACK_IMPORTED_MODULE_4__settings__","__WEBPACK_IMPORTED_MODULE_5__statsv__","__WEBPACK_IMPORTED_MODULE_6__syncUserSettings__","linkTitle","render","statsv","syncUserSettings","./src/changeListeners/linkTitle.js","destroyTitleAttr","$el","restoreTitleAttr","hasPrevActiveLink","activeLink","./src/changeListeners/render.js","previewBehavior","shouldShow","__WEBPACK_IMPORTED_MODULE_0__ui_renderer__","fetchResponse","activeEvent","./src/changeListeners/settings.js","appendTo","document","body","setEnabled","showHelp","toggleHelp","./src/changeListeners/statsv.js","track","data","./src/changeListeners/syncUserSettings.js","syncIfChanged","setPreviewCount","setIsEnabled","reducer","prop","sync","current","./src/constants.js","BUCKETS","pixelRatio","bracketedDevicePixelRatio","off","on","control","THUMBNAIL_SIZE","EXTRACT_LENGTH","./src/counts.js","getEditCountBucket","count","bucket","getPreviewCountBucket","./src/experiments.js","createExperiments","mwExperiments","weightedBoolean","trueWeight","getBucket","buckets","true","false","./src/formatter.js","formatPlainTextExtract","plainTextExtract","extract","removeParentheticals","removeTrailingEllipsis","makeTitleInExtractBold","regExp","escapedTitle","elements","boldIdentifier","snip","replace","trim","RegExp","escape","each","index","part","createTextNode","ch","level","charAt","./src/gateway/index.js","createGateway","__WEBPACK_IMPORTED_MODULE_1__mediawiki__","Api","__WEBPACK_IMPORTED_MODULE_0__constants__","__WEBPACK_IMPORTED_MODULE_2__rest__","ajax","__WEBPACK_IMPORTED_MODULE_3__restFormatters__","./src/gateway/mediawiki.js","createMediaWikiApiGateway","api","formatversion","redirects","exintro","exchars","explaintext","piprop","pithumbsize","pilicense","rvprop","inprop","titles","smaxage","CACHE_LIFETIME","maxage","uselang","headers","X-Analytics","extractPageFromResponse","convertPageToModel","query","pages","__WEBPACK_IMPORTED_MODULE_1__formatter__","__WEBPACK_IMPORTED_MODULE_0__preview_model__","canonicalurl","pagelanguagehtmlcode","pagelanguagedir","thumbnail","./src/gateway/rest.js","createRESTBaseGateway","extractParser","url","RESTBASE_ENDPOINT","encodeURIComponent","Accept","RESTBASE_PROFILE","Deferred","resolve","jqXHR","status","reject","promise","generateThumbnailData","original","thumbSize","filename","width","height","parts","source","lastPart","substr","floor","Title","getUrl","lang","dir","originalimage","./src/gateway/restFormatters.js","parseHTMLResponse","extract_html","__WEBPACK_IMPORTED_MODULE_0__formatter__","parseHTML","parsePlainTextResponse","./src/getUserBucket.js","getUserBucket","experiments","experimentGroupSize","./src/index.js","getStatsvTracker","__WEBPACK_IMPORTED_MODULE_11__instrumentation_statsv__","noop","getEventLoggingTracker","__WEBPACK_IMPORTED_MODULE_12__instrumentation_eventLogging__","registerChangeListeners","actions","settingsDialog","statsvTracker","__WEBPACK_IMPORTED_MODULE_6__changeListener__","__WEBPACK_IMPORTED_MODULE_13__changeListeners__","__WEBPACK_IMPORTED_MODULE_0_redux__","__WEBPACK_IMPORTED_MODULE_1_redux_thunk__","__WEBPACK_IMPORTED_MODULE_2__gateway__","__WEBPACK_IMPORTED_MODULE_3__userSettings__","__WEBPACK_IMPORTED_MODULE_4__previewBehavior__","__WEBPACK_IMPORTED_MODULE_5__ui_settingsDialog__","__WEBPACK_IMPORTED_MODULE_7__isEnabled__","__WEBPACK_IMPORTED_MODULE_8__title__","__WEBPACK_IMPORTED_MODULE_9__ui_renderer__","__WEBPACK_IMPORTED_MODULE_10__experiments__","__WEBPACK_IMPORTED_MODULE_14__actions__","__WEBPACK_IMPORTED_MODULE_15__reducers__","__WEBPACK_IMPORTED_MODULE_16__integrations_mwpopups__","__WEBPACK_IMPORTED_MODULE_17__getUserBucket__","BLACKLISTED_LINKS","requestIdleCallback","userBucket","generateRandomSessionId","storage","__REDUX_DEVTOOLS_EXTENSION_COMPOSE__","popups","hook","add","$container","invalidLinksSelector","validLinkSelector","mwTitle","Redux","ReduxThunk","./src/instrumentation/eventLogging.js","navigator","isFunction","sendBeacon","./src/instrumentation/statsv.js","bucketingRate","./src/integrations/mwpopups.js","createMwPopups","./src/isEnabled.js","hasIsEnabled","getIsEnabled","./src/preview/model.js","createModel","languageCode","languageDirection","processedExtract","processExtract","TYPE_GENERIC","TYPE_PAGE","createNullModel","./src/previewBehavior.js","createPreviewBehavior","rawTitle","settingsUrl","isBetaFeature","newFromText","previewAbandon","./src/reducers/eventLogging.js","getBaseData","bootAction","pageTitleSource","namespaceIdSource","pageIdSource","popupEnabled","previewCountBucket","__WEBPACK_IMPORTED_MODULE_2__counts__","hovercardsSuppressedByGadget","editCountBucket","createEvent","interaction","actionData","linkInteractionToken","pageTitleHover","namespaceIdHover","timeToPreviewShow","previewType","perceivedWait","createClosingEvent","totalInteractionTime","round","finished","started","finalized","nextCount","newState","actionTypesWithTokens","__WEBPACK_IMPORTED_MODULE_1__nextState__","link","isUserDwelling","./src/reducers/index.js","__WEBPACK_IMPORTED_MODULE_0__eventLogging__","__WEBPACK_IMPORTED_MODULE_1__preview__","__WEBPACK_IMPORTED_MODULE_2__settings__","__WEBPACK_IMPORTED_MODULE_3__statsv__","./src/reducers/nextState.js","nextState","updates","key","./src/reducers/preview.js","./src/reducers/settings.js","./src/reducers/statsv.js","fetchStartedAt","linkDwellStartedAt","./src/title.js","getTitle","href","linkHref","matches","queryLength","titleRegex","Uri","host","location","hostname","exec","path","decodeURIComponent","isValid","contentNamespaces","inArray","fromElement","./src/ui/renderer.js","createPokeyMasks","container","html","init","model","createEmptyPreview","createPreview","target","templateData","createThumbnail","hasThumbnail","template","find","isTall","extractMsg","msg","readMsg","behavior","layout","createLayout","pageX","pageY","clientY","clientRects","getClientRects","offset","scrollTop","$window","SIZES","pokeySize","layoutPreview","getClasses","landscapeImage","__WEBPACK_IMPORTED_MODULE_0__wait__","bindBehavior","hover","stopPropagation","fadeInClass","fadeOutClass","hasClass","removeClass","addClass","remove","rawThumbnail","tall","thumbWidth","thumbHeight","x","clipPath","devicePixelRatio","w","portraitImage","createThumbnailElement","className","thumbnailWidth","thumbnailHeight","$thumbnailSVGImage","nsSvg","createElementNS","setAttributeNS","clip-path","xmlns","isPreviewTall","eventData","linkData","windowData","flippedX","flippedY","offsetTop","getClosestYPosition","top","clientTop","offsetLeft","left","landscapePopupWidth","portraitPopupWidth","classes","predefinedLandscapeImageHeight","popup","css","outerHeight","removeAttribute","setAttribute","rects","isTop","deltaY","minY","rect","abs","bottom","ceil","./src/ui/settingsDialog.js","createSettingsDialogRenderer","$dialog","$overlay","createSettingsDialog","selected","getSelectedSetting","outerWidth","visible","choices","description","image","isChecked","heading","closeLabel","saveLabel","helpText","okLabel","descriptionText","val","pg","fn","disablePopups","./src/userSettings.js","createUserSettings","IS_ENABLED_KEY","set","Boolean","PREVIEW_COUNT_KEY","parseInt","isNaN","./src/wait.js","wait","delay","setTimeout"],"mappings":"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","file":"index.js","sourcesContent":["/*@nomin*/\n/******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId]) {\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\ti: moduleId,\n/******/ \t\t\tl: false,\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.l = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n/******/\n/******/ \t// identity function for calling harmony imports with the correct context\n/******/ \t__webpack_require__.i = function(value) { return value; };\n/******/\n/******/ \t// define getter function for harmony exports\n/******/ \t__webpack_require__.d = function(exports, name, getter) {\n/******/ \t\tif(!__webpack_require__.o(exports, name)) {\n/******/ \t\t\tObject.defineProperty(exports, name, {\n/******/ \t\t\t\tconfigurable: false,\n/******/ \t\t\t\tenumerable: true,\n/******/ \t\t\t\tget: getter\n/******/ \t\t\t});\n/******/ \t\t}\n/******/ \t};\n/******/\n/******/ \t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t__webpack_require__.n = function(module) {\n/******/ \t\tvar getter = module && module.__esModule ?\n/******/ \t\t\tfunction getDefault() { return module['default']; } :\n/******/ \t\t\tfunction getModuleExports() { return module; };\n/******/ \t\t__webpack_require__.d(getter, 'a', getter);\n/******/ \t\treturn getter;\n/******/ \t};\n/******/\n/******/ \t// Object.prototype.hasOwnProperty.call\n/******/ \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"\";\n/******/\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(__webpack_require__.s = \"./src/index.js\");\n/******/ })\n/************************************************************************/\n/******/ ({\n\n/***/ \"./node_modules/redux-thunk/dist/redux-thunk.min.js\":\n/***/ (function(module, exports, __webpack_require__) {\n\n!function(t,e){ true?module.exports=e():\"function\"==typeof define&&define.amd?define([],e):\"object\"==typeof exports?exports.ReduxThunk=e():t.ReduxThunk=e()}(this,function(){return function(t){function e(o){if(n[o])return n[o].exports;var r=n[o]={exports:{},id:o,loaded:!1};return t[o].call(r.exports,r,r.exports,e),r.loaded=!0,r.exports}var n={};return e.m=t,e.c=n,e.p=\"\",e(0)}([function(t,e,n){t.exports=n(1)},function(t,e){\"use strict\";function n(t){return function(e){var n=e.dispatch,o=e.getState;return function(e){return function(r){return\"function\"==typeof r?r(n,o,t):e(r)}}}}e.__esModule=!0;var o=n();o.withExtraArgument=n,e.default=o}])});\n\n/***/ }),\n\n/***/ \"./node_modules/redux/dist/redux.min.js\":\n/***/ (function(module, exports, __webpack_require__) {\n\n!function(t,e){ true?module.exports=e():\"function\"==typeof define&&define.amd?define([],e):\"object\"==typeof exports?exports.Redux=e():t.Redux=e()}(this,function(){return function(t){function e(r){if(n[r])return n[r].exports;var o=n[r]={exports:{},id:r,loaded:!1};return t[r].call(o.exports,o,o.exports,e),o.loaded=!0,o.exports}var n={};return e.m=t,e.c=n,e.p=\"\",e(0)}([function(t,e,n){\"use strict\";function r(t){return t&&t.__esModule?t:{\"default\":t}}e.__esModule=!0,e.compose=e.applyMiddleware=e.bindActionCreators=e.combineReducers=e.createStore=void 0;var o=n(2),u=r(o),i=n(7),c=r(i),a=n(6),f=r(a),s=n(5),d=r(s),l=n(1),p=r(l),y=n(3);r(y);e.createStore=u[\"default\"],e.combineReducers=c[\"default\"],e.bindActionCreators=f[\"default\"],e.applyMiddleware=d[\"default\"],e.compose=p[\"default\"]},function(t,e){\"use strict\";function n(){for(var t=arguments.length,e=Array(t),n=0;t>n;n++)e[n]=arguments[n];if(0===e.length)return function(t){return t};if(1===e.length)return e[0];var r=e[e.length-1],o=e.slice(0,-1);return function(){return o.reduceRight(function(t,e){return e(t)},r.apply(void 0,arguments))}}e.__esModule=!0,e[\"default\"]=n},function(t,e,n){\"use strict\";function r(t){return t&&t.__esModule?t:{\"default\":t}}function o(t,e,n){function r(){b===h&&(b=h.slice())}function u(){return v}function c(t){if(\"function\"!=typeof t)throw Error(\"Expected listener to be a function.\");var e=!0;return r(),b.push(t),function(){if(e){e=!1,r();var n=b.indexOf(t);b.splice(n,1)}}}function s(t){if(!(0,i[\"default\"])(t))throw Error(\"Actions must be plain objects. Use custom middleware for async actions.\");if(void 0===t.type)throw Error('Actions may not have an undefined \"type\" property. Have you misspelled a constant?');if(m)throw Error(\"Reducers may not dispatch actions.\");try{m=!0,v=y(v,t)}finally{m=!1}for(var e=h=b,n=0;e.length>n;n++)e[n]();return t}function d(t){if(\"function\"!=typeof t)throw Error(\"Expected the nextReducer to be a function.\");y=t,s({type:f.INIT})}function l(){var t,e=c;return t={subscribe:function(t){function n(){t.next&&t.next(u())}if(\"object\"!=typeof t)throw new TypeError(\"Expected the observer to be an object.\");n();var r=e(n);return{unsubscribe:r}}},t[a[\"default\"]]=function(){return this},t}var p;if(\"function\"==typeof e&&void 0===n&&(n=e,e=void 0),void 0!==n){if(\"function\"!=typeof n)throw Error(\"Expected the enhancer to be a function.\");return n(o)(t,e)}if(\"function\"!=typeof t)throw Error(\"Expected the reducer to be a function.\");var y=t,v=e,h=[],b=h,m=!1;return s({type:f.INIT}),p={dispatch:s,subscribe:c,getState:u,replaceReducer:d},p[a[\"default\"]]=l,p}e.__esModule=!0,e.ActionTypes=void 0,e[\"default\"]=o;var u=n(4),i=r(u),c=n(12),a=r(c),f=e.ActionTypes={INIT:\"@@redux/INIT\"}},function(t,e){\"use strict\";function n(t){\"undefined\"!=typeof console&&\"function\"==typeof console.error&&console.error(t);try{throw Error(t)}catch(e){}}e.__esModule=!0,e[\"default\"]=n},function(t,e,n){function r(t){if(!i(t)||p.call(t)!=c||u(t))return!1;var e=o(t);if(null===e)return!0;var n=d.call(e,\"constructor\")&&e.constructor;return\"function\"==typeof n&&n instanceof n&&s.call(n)==l}var o=n(8),u=n(9),i=n(11),c=\"[object Object]\",a=Function.prototype,f=Object.prototype,s=a.toString,d=f.hasOwnProperty,l=s.call(Object),p=f.toString;t.exports=r},function(t,e,n){\"use strict\";function r(t){return t&&t.__esModule?t:{\"default\":t}}function o(){for(var t=arguments.length,e=Array(t),n=0;t>n;n++)e[n]=arguments[n];return function(t){return function(n,r,o){var i=t(n,r,o),a=i.dispatch,f=[],s={getState:i.getState,dispatch:function(t){return a(t)}};return f=e.map(function(t){return t(s)}),a=c[\"default\"].apply(void 0,f)(i.dispatch),u({},i,{dispatch:a})}}}e.__esModule=!0;var u=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(t[r]=n[r])}return t};e[\"default\"]=o;var i=n(1),c=r(i)},function(t,e){\"use strict\";function n(t,e){return function(){return e(t.apply(void 0,arguments))}}function r(t,e){if(\"function\"==typeof t)return n(t,e);if(\"object\"!=typeof t||null===t)throw Error(\"bindActionCreators expected an object or a function, instead received \"+(null===t?\"null\":typeof t)+'. Did you write \"import ActionCreators from\" instead of \"import * as ActionCreators from\"?');for(var r=Object.keys(t),o={},u=0;r.length>u;u++){var i=r[u],c=t[i];\"function\"==typeof c&&(o[i]=n(c,e))}return o}e.__esModule=!0,e[\"default\"]=r},function(t,e,n){\"use strict\";function r(t){return t&&t.__esModule?t:{\"default\":t}}function o(t,e){var n=e&&e.type,r=n&&'\"'+n+'\"'||\"an action\";return\"Given action \"+r+', reducer \"'+t+'\" returned undefined. To ignore an action, you must explicitly return the previous state.'}function u(t){Object.keys(t).forEach(function(e){var n=t[e],r=n(void 0,{type:c.ActionTypes.INIT});if(void 0===r)throw Error('Reducer \"'+e+'\" returned undefined during initialization. If the state passed to the reducer is undefined, you must explicitly return the initial state. The initial state may not be undefined.');var o=\"@@redux/PROBE_UNKNOWN_ACTION_\"+Math.random().toString(36).substring(7).split(\"\").join(\".\");if(void 0===n(void 0,{type:o}))throw Error('Reducer \"'+e+'\" returned undefined when probed with a random type. '+(\"Don't try to handle \"+c.ActionTypes.INIT+' or other actions in \"redux/*\" ')+\"namespace. They are considered private. Instead, you must return the current state for any unknown actions, unless it is undefined, in which case you must return the initial state, regardless of the action type. The initial state may not be undefined.\")})}function i(t){for(var e=Object.keys(t),n={},r=0;e.length>r;r++){var i=e[r];\"function\"==typeof t[i]&&(n[i]=t[i])}var c,a=Object.keys(n);try{u(n)}catch(f){c=f}return function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},e=arguments[1];if(c)throw c;for(var r=!1,u={},i=0;a.length>i;i++){var f=a[i],s=n[f],d=t[f],l=s(d,e);if(void 0===l){var p=o(f,e);throw Error(p)}u[f]=l,r=r||l!==d}return r?u:t}}e.__esModule=!0,e[\"default\"]=i;var c=n(2),a=n(4),f=(r(a),n(3));r(f)},function(t,e,n){var r=n(10),o=r(Object.getPrototypeOf,Object);t.exports=o},function(t,e){function n(t){var e=!1;if(null!=t&&\"function\"!=typeof t.toString)try{e=!!(t+\"\")}catch(n){}return e}t.exports=n},function(t,e){function n(t,e){return function(n){return t(e(n))}}t.exports=n},function(t,e){function n(t){return!!t&&\"object\"==typeof t}t.exports=n},function(t,e,n){t.exports=n(13)},function(t,e,n){(function(t){\"use strict\";function r(t){return t&&t.__esModule?t:{\"default\":t}}Object.defineProperty(e,\"__esModule\",{value:!0});var o=n(14),u=r(o),i=void 0;void 0!==t?i=t:\"undefined\"!=typeof window&&(i=window);var c=(0,u[\"default\"])(i);e[\"default\"]=c}).call(e,function(){return this}())},function(t,e){\"use strict\";function n(t){var e,n=t.Symbol;return\"function\"==typeof n?n.observable?e=n.observable:(e=n(\"observable\"),n.observable=e):e=\"@@observable\",e}Object.defineProperty(e,\"__esModule\",{value:!0}),e[\"default\"]=n}])});\n\n/***/ }),\n\n/***/ \"./src/actionTypes.js\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/**\n * @module actionTypes\n */\n\n/* harmony default export */ __webpack_exports__[\"a\"] = ({\n\tBOOT: 'BOOT',\n\tLINK_DWELL: 'LINK_DWELL',\n\tABANDON_START: 'ABANDON_START',\n\tABANDON_END: 'ABANDON_END',\n\tLINK_CLICK: 'LINK_CLICK',\n\tFETCH_START: 'FETCH_START',\n\tFETCH_END: 'FETCH_END',\n\tFETCH_COMPLETE: 'FETCH_COMPLETE',\n\tFETCH_FAILED: 'FETCH_FAILED',\n\tPREVIEW_DWELL: 'PREVIEW_DWELL',\n\tPREVIEW_SHOW: 'PREVIEW_SHOW',\n\tPREVIEW_CLICK: 'PREVIEW_CLICK',\n\tSETTINGS_SHOW: 'SETTINGS_SHOW',\n\tSETTINGS_HIDE: 'SETTINGS_HIDE',\n\tSETTINGS_CHANGE: 'SETTINGS_CHANGE',\n\tEVENT_LOGGED: 'EVENT_LOGGED',\n\tSTATSV_LOGGED: 'STATSV_LOGGED'\n});\n\n\n/***/ }),\n\n/***/ \"./src/actions.js\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\nObject.defineProperty(__webpack_exports__, \"__esModule\", { value: true });\n/* harmony export (immutable) */ __webpack_exports__[\"boot\"] = boot;\n/* harmony export (immutable) */ __webpack_exports__[\"fetch\"] = fetch;\n/* harmony export (immutable) */ __webpack_exports__[\"linkDwell\"] = linkDwell;\n/* harmony export (immutable) */ __webpack_exports__[\"abandon\"] = abandon;\n/* harmony export (immutable) */ __webpack_exports__[\"linkClick\"] = linkClick;\n/* harmony export (immutable) */ __webpack_exports__[\"previewDwell\"] = previewDwell;\n/* harmony export (immutable) */ __webpack_exports__[\"previewShow\"] = previewShow;\n/* harmony export (immutable) */ __webpack_exports__[\"showSettings\"] = showSettings;\n/* harmony export (immutable) */ __webpack_exports__[\"hideSettings\"] = hideSettings;\n/* harmony export (immutable) */ __webpack_exports__[\"saveSettings\"] = saveSettings;\n/* harmony export (immutable) */ __webpack_exports__[\"eventLogged\"] = eventLogged;\n/* harmony export (immutable) */ __webpack_exports__[\"statsvLogged\"] = statsvLogged;\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__actionTypes__ = __webpack_require__(\"./src/actionTypes.js\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__wait__ = __webpack_require__(\"./src/wait.js\");\n/**\n * @module actions\n */\n\n\n\n\nvar $ = jQuery,\n\tmw = window.mediaWiki,\n\n\t// See the following for context around this value.\n\t//\n\t// * https://phabricator.wikimedia.org/T161284\n\t// * https://phabricator.wikimedia.org/T70861#3129780\n\tFETCH_START_DELAY = 150, // ms.\n\n\t// The delay after which a FETCH_COMPLETE action should be dispatched.\n\t//\n\t// If the API endpoint responds faster than 500 ms (or, say, the API\n\t// response is served from the UA's cache), then we introduce a delay of\n\t// 500 - t to make the preview delay consistent to the user.\n\tFETCH_COMPLETE_TARGET_DELAY = 500, // ms.\n\n\tABANDON_END_DELAY = 300; // ms.\n\n/**\n * Mixes in timing information to an action.\n *\n * Warning: the `baseAction` parameter is modified and returned.\n *\n * @param {Object} baseAction\n * @return {Object}\n */\nfunction timedAction( baseAction ) {\n\tbaseAction.timestamp = mw.now();\n\n\treturn baseAction;\n}\n\n/**\n * Represents Page Previews booting.\n *\n * When a Redux store is created, the `@@INIT` action is immediately\n * dispatched to it. To avoid overriding the term, we refer to booting rather\n * than initializing.\n *\n * Page Previews persists critical pieces of information to local storage.\n * Since reading from and writing to local storage are synchronous, Page\n * Previews is booted when the browser is idle (using\n * [`mw.requestIdleCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback))\n * so as not to impact latency-critical events.\n *\n * @param {Boolean} isEnabled See `isEnabled.js`\n * @param {mw.user} user\n * @param {ext.popups.UserSettings} userSettings\n * @param {Function} generateToken\n * @param {mw.Map} config The config of the MediaWiki client-side application,\n * i.e. `mw.config`\n * @returns {Object}\n */\nfunction boot(\n\tisEnabled,\n\tuser,\n\tuserSettings,\n\tgenerateToken,\n\tconfig\n) {\n\tvar editCount = config.get( 'wgUserEditCount' ),\n\t\tpreviewCount = userSettings.getPreviewCount();\n\n\treturn {\n\t\ttype: __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].BOOT,\n\t\tisEnabled: isEnabled,\n\t\tisNavPopupsEnabled: config.get( 'wgPopupsConflictsWithNavPopupGadget' ),\n\t\tsessionToken: user.sessionId(),\n\t\tpageToken: generateToken(),\n\t\tpage: {\n\t\t\ttitle: config.get( 'wgTitle' ),\n\t\t\tnamespaceID: config.get( 'wgNamespaceNumber' ),\n\t\t\tid: config.get( 'wgArticleId' )\n\t\t},\n\t\tuser: {\n\t\t\tisAnon: user.isAnon(),\n\t\t\teditCount: editCount,\n\t\t\tpreviewCount: previewCount\n\t\t}\n\t};\n}\n\n/**\n * Represents Page Previews fetching data via the gateway.\n *\n * @param {Gateway} gateway\n * @param {mw.Title} title\n * @param {Element} el\n * @param {String} token The unique token representing the link interaction that\n * triggered the fetch\n * @return {Redux.Thunk}\n */\nfunction fetch( gateway, title, el, token ) {\n\tvar titleText = title.getPrefixedDb(),\n\t\tnamespaceID = title.namespace;\n\n\treturn function ( dispatch ) {\n\t\tvar request;\n\n\t\tdispatch( timedAction( {\n\t\t\ttype: __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].FETCH_START,\n\t\t\tel: el,\n\t\t\ttitle: titleText,\n\t\t\tnamespaceID: namespaceID\n\t\t} ) );\n\n\t\trequest = gateway.getPageSummary( titleText )\n\t\t\t.then( function ( result ) {\n\t\t\t\tdispatch( timedAction( {\n\t\t\t\t\ttype: __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].FETCH_END,\n\t\t\t\t\tel: el\n\t\t\t\t} ) );\n\n\t\t\t\treturn result;\n\t\t\t} )\n\t\t\t// FIXME: Convert to Promises A/A+ when \"T124742: Upgrade to jQuery 3\" is\n\t\t\t// fully rolled out by changing fail to catch, and re-throwing the error\n\t\t\t// to keep the promise in a rejected state.\n\t\t\t.fail( function () {\n\t\t\t\tdispatch( {\n\t\t\t\t\ttype: __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].FETCH_FAILED,\n\t\t\t\t\tel: el\n\t\t\t\t} );\n\t\t\t} );\n\n\t\treturn $.when( request, __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__wait__[\"a\" /* default */])( FETCH_COMPLETE_TARGET_DELAY - FETCH_START_DELAY ) )\n\t\t\t.then( function ( result ) {\n\t\t\t\tdispatch( timedAction( {\n\t\t\t\t\ttype: __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].FETCH_COMPLETE,\n\t\t\t\t\tel: el,\n\t\t\t\t\tresult: result,\n\t\t\t\t\ttoken: token\n\t\t\t\t} ) );\n\t\t\t} );\n\t};\n}\n\n/**\n * Represents the user dwelling on a link, either by hovering over it with\n * their mouse or by focussing it using their keyboard or an assistive device.\n *\n * @param {mw.Title} title\n * @param {Element} el\n * @param {Event} event\n * @param {Gateway} gateway\n * @param {Function} generateToken\n * @return {Redux.Thunk}\n */\nfunction linkDwell( title, el, event, gateway, generateToken ) {\n\tvar token = generateToken(),\n\t\ttitleText = title.getPrefixedDb(),\n\t\tnamespaceID = title.namespace;\n\n\treturn function ( dispatch, getState ) {\n\t\tvar action = timedAction( {\n\t\t\ttype: __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].LINK_DWELL,\n\t\t\tel: el,\n\t\t\tevent: event,\n\t\t\ttoken: token,\n\t\t\ttitle: titleText,\n\t\t\tnamespaceID: namespaceID\n\t\t} );\n\n\t\t// Has the new generated token been accepted?\n\t\tfunction isNewInteraction() {\n\t\t\treturn getState().preview.activeToken === token;\n\t\t}\n\n\t\tdispatch( action );\n\n\t\tif ( !isNewInteraction() ) {\n\t\t\treturn;\n\t\t}\n\n\t\t__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__wait__[\"a\" /* default */])( FETCH_START_DELAY )\n\t\t\t.then( function () {\n\t\t\t\tvar previewState = getState().preview;\n\n\t\t\t\tif ( previewState.enabled && isNewInteraction() ) {\n\t\t\t\t\tdispatch( fetch( gateway, title, el, token ) );\n\t\t\t\t}\n\t\t\t} );\n\t};\n}\n\n/**\n * Represents the user abandoning a link, either by moving their mouse away\n * from it or by shifting focus to another UI element using their keyboard or\n * an assistive device, or abandoning a preview by moving their mouse away\n * from it.\n *\n * @return {Redux.Thunk}\n */\nfunction abandon() {\n\treturn function ( dispatch, getState ) {\n\t\tvar token = getState().preview.activeToken;\n\n\t\tif ( !token ) {\n\t\t\treturn;\n\t\t}\n\n\t\tdispatch( timedAction( {\n\t\t\ttype: __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].ABANDON_START,\n\t\t\ttoken: token\n\t\t} ) );\n\n\t\t__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__wait__[\"a\" /* default */])( ABANDON_END_DELAY )\n\t\t\t.then( function () {\n\t\t\t\tdispatch( {\n\t\t\t\t\ttype: __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].ABANDON_END,\n\t\t\t\t\ttoken: token\n\t\t\t\t} );\n\t\t\t} );\n\t};\n}\n\n/**\n * Represents the user clicking on a link with their mouse, keyboard, or an\n * assistive device.\n *\n * @param {Element} el\n * @return {Object}\n */\nfunction linkClick( el ) {\n\treturn timedAction( {\n\t\ttype: __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].LINK_CLICK,\n\t\tel: el\n\t} );\n}\n\n/**\n * Represents the user dwelling on a preview with their mouse.\n *\n * @return {Object}\n */\nfunction previewDwell() {\n\treturn {\n\t\ttype: __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].PREVIEW_DWELL\n\t};\n}\n\n/**\n * Represents a preview being shown to the user.\n *\n * This action is dispatched by the `./changeListeners/render.js` change\n * listener.\n *\n * @param {String} token\n * @return {Object}\n */\nfunction previewShow( token ) {\n\treturn timedAction( {\n\t\ttype: __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].PREVIEW_SHOW,\n\t\ttoken: token\n\t} );\n}\n\n/**\n * Represents the user clicking either the \"Enable previews\" footer menu link,\n * or the \"cog\" icon that's present on each preview.\n *\n * @return {Object}\n */\nfunction showSettings() {\n\treturn {\n\t\ttype: __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].SETTINGS_SHOW\n\t};\n}\n\n/**\n * Represents the user closing the settings dialog and saving their settings.\n *\n * @return {Object}\n */\nfunction hideSettings() {\n\treturn {\n\t\ttype: __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].SETTINGS_HIDE\n\t};\n}\n\n/**\n * Represents the user saving their settings.\n *\n * N.B. This action returns a Redux.Thunk not because it needs to perform\n * asynchronous work, but because it needs to query the global state for the\n * current enabled state. In order to keep the enabled state in a single\n * place (the preview reducer), we query it and dispatch it as `wasEnabled`\n * so that other reducers (like settings) can act on it without having to\n * duplicate the `enabled` state locally.\n * See doc/adr/0003-keep-enabled-state-only-in-preview-reducer.md for more\n * details.\n *\n * @param {Boolean} enabled if previews are enabled or not\n * @return {Redux.Thunk}\n */\nfunction saveSettings( enabled ) {\n\treturn function ( dispatch, getState ) {\n\t\tdispatch( {\n\t\t\ttype: __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].SETTINGS_CHANGE,\n\t\t\twasEnabled: getState().preview.enabled,\n\t\t\tenabled: enabled\n\t\t} );\n\t};\n}\n\n/**\n * Represents the queued event being logged `changeListeners/eventLogging.js`\n * change listener.\n *\n * @param {Object} event\n * @return {Object}\n */\nfunction eventLogged( event ) {\n\treturn {\n\t\ttype: __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].EVENT_LOGGED,\n\t\tevent: event\n\t};\n}\n\n/**\n * Represents the queued statsv event being logged.\n * See `mw.popups.changeListeners.statsv` change listener.\n *\n * @return {Object}\n */\nfunction statsvLogged() {\n\treturn {\n\t\ttype: __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].STATSV_LOGGED\n\t};\n}\n\n\n/***/ }),\n\n/***/ \"./src/changeListener.js\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony export (immutable) */ __webpack_exports__[\"a\"] = registerChangeListener;\n/**\n * @module changeListener\n */\n\n/**\n * @typedef {Function} ext.popups.ChangeListener\n * @param {Object} prevState The previous state\n * @param {Object} state The current state\n */\n\n/**\n * Registers a change listener, which is bound to the\n * [store](http://redux.js.org/docs/api/Store.html).\n *\n * A change listener is a function that is only invoked when the state in the\n * [store](http://redux.js.org/docs/api/Store.html) changes. N.B. that there\n * may not be a 1:1 correspondence with actions being dispatched to the store\n * and the state in the store changing.\n *\n * See [Store#subscribe](http://redux.js.org/docs/api/Store.html#subscribe)\n * for more information about what change listeners may and may not do.\n *\n * @param {Redux.Store} store\n * @param {ext.popups.ChangeListener} callback\n */\nfunction registerChangeListener( store, callback ) {\n\t// This function is based on the example in [the documentation for\n\t// Store#subscribe](http://redux.js.org/docs/api/Store.html#subscribe),\n\t// which was written by Dan Abramov.\n\n\tvar state;\n\n\tstore.subscribe( function () {\n\t\tvar prevState = state;\n\n\t\tstate = store.getState();\n\n\t\tif ( prevState !== state ) {\n\t\t\tcallback( prevState, state );\n\t\t}\n\t} );\n}\n\n\n/***/ }),\n\n/***/ \"./src/changeListeners/eventLogging.js\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony export (immutable) */ __webpack_exports__[\"a\"] = eventLogging;\n/**\n * @module changeListeners/eventLogging\n */\n\nvar $ = jQuery;\n\n/**\n * Creates an instance of the event logging change listener.\n *\n * When an event is enqueued it'll be logged using the schema. Since it's the\n * responsibility of Event Logging (and the UA) to deliver logged events,\n * `EVENT_LOGGED` is immediately dispatched rather than waiting for some\n * indicator of completion.\n *\n * @param {Object} boundActions\n * @param {EventTracker} eventLoggingTracker\n * @return {ext.popups.ChangeListener}\n */\nfunction eventLogging( boundActions, eventLoggingTracker ) {\n\treturn function ( _, state ) {\n\t\tvar eventLogging = state.eventLogging,\n\t\t\tevent = eventLogging.event;\n\n\t\tif ( !event ) {\n\t\t\treturn;\n\t\t}\n\n\t\tevent = $.extend( true, {}, eventLogging.baseData, event );\n\t\teventLoggingTracker( 'event.Popups', event );\n\t\t// Dispatch the eventLogged action so that the state tree can be\n\t\t// cleared/updated.\n\t\tboundActions.eventLogged( event );\n\t};\n}\n\n\n/***/ }),\n\n/***/ \"./src/changeListeners/footerLink.js\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony export (immutable) */ __webpack_exports__[\"a\"] = footerLink;\n/**\n * @module changeListeners/footerLink\n */\n\nvar mw = window.mediaWiki,\n\t$ = jQuery;\n\n/**\n * Creates the link element and appends it to the footer element.\n *\n * The following elements are considered to be the footer element (highest\n * priority to lowest):\n *\n * # `#footer-places`\n * # `#f-list`\n * # The parent element of `#footer li`, which is either an `ol` or `ul`.\n *\n * @return {jQuery} The link element\n */\nfunction createFooterLink() {\n\tvar $link = $( '<li>' ).append(\n\t\t\t$( '<a>' )\n\t\t\t\t.attr( 'href', '#' )\n\t\t\t\t.text( mw.message( 'popups-settings-enable' ).text() )\n\t\t),\n\t\t$footer;\n\n\t// As yet, we don't know whether the link should be visible.\n\t$link.hide();\n\n\t// From https://en.wikipedia.org/wiki/MediaWiki:Gadget-ReferenceTooltips.js,\n\t// which was written by Yair rand <https://en.wikipedia.org/wiki/User:Yair_rand>.\n\t$footer = $( '#footer-places, #f-list' );\n\n\tif ( $footer.length === 0 ) {\n\t\t$footer = $( '#footer li' ).parent();\n\t}\n\n\t$footer.append( $link );\n\n\treturn $link;\n}\n\n/**\n * Creates an instance of the footer link change listener.\n *\n * The change listener covers the following behaviour:\n *\n * * The \"Enable previews\" link (the \"link\") is appended to the footer menu\n * (see `createFooterLink` above).\n * * When Page Previews are disabled, then the link is shown; otherwise, the\n * link is hidden.\n * * When the user clicks the link, then the `showSettings` bound action\n * creator is called.\n *\n * @param {Object} boundActions\n * @return {ext.popups.ChangeListener}\n */\nfunction footerLink( boundActions ) {\n\tvar $footerLink;\n\n\treturn function ( prevState, state ) {\n\t\tif ( $footerLink === undefined ) {\n\t\t\t$footerLink = createFooterLink();\n\t\t\t$footerLink.click( function ( e ) {\n\t\t\t\te.preventDefault();\n\t\t\t\tboundActions.showSettings();\n\t\t\t} );\n\t\t}\n\n\t\tif ( state.settings.shouldShowFooterLink ) {\n\t\t\t$footerLink.show();\n\t\t} else {\n\t\t\t$footerLink.hide();\n\t\t}\n\t};\n}\n\n\n/***/ }),\n\n/***/ \"./src/changeListeners/index.js\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__footerLink__ = __webpack_require__(\"./src/changeListeners/footerLink.js\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__eventLogging__ = __webpack_require__(\"./src/changeListeners/eventLogging.js\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__linkTitle__ = __webpack_require__(\"./src/changeListeners/linkTitle.js\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__render__ = __webpack_require__(\"./src/changeListeners/render.js\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__settings__ = __webpack_require__(\"./src/changeListeners/settings.js\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__statsv__ = __webpack_require__(\"./src/changeListeners/statsv.js\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__syncUserSettings__ = __webpack_require__(\"./src/changeListeners/syncUserSettings.js\");\n\n\n\n\n\n\n\n\n/* harmony default export */ __webpack_exports__[\"a\"] = ({\n\tfooterLink: __WEBPACK_IMPORTED_MODULE_0__footerLink__[\"a\" /* default */],\n\teventLogging: __WEBPACK_IMPORTED_MODULE_1__eventLogging__[\"a\" /* default */],\n\tlinkTitle: __WEBPACK_IMPORTED_MODULE_2__linkTitle__[\"a\" /* default */],\n\trender: __WEBPACK_IMPORTED_MODULE_3__render__[\"a\" /* default */],\n\tsettings: __WEBPACK_IMPORTED_MODULE_4__settings__[\"a\" /* default */],\n\tstatsv: __WEBPACK_IMPORTED_MODULE_5__statsv__[\"a\" /* default */],\n\tsyncUserSettings: __WEBPACK_IMPORTED_MODULE_6__syncUserSettings__[\"a\" /* default */]\n});\n\n\n/***/ }),\n\n/***/ \"./src/changeListeners/linkTitle.js\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony export (immutable) */ __webpack_exports__[\"a\"] = linkTitle;\nvar $ = jQuery;\n\n/**\n * Creates an instance of the link title change listener.\n *\n * While the user dwells on a link, then it becomes the active link. The\n * change listener will remove a link's `title` attribute while it's the\n * active link.\n *\n * @return {ext.popups.ChangeListener}\n */\nfunction linkTitle() {\n\tvar title;\n\n\t/**\n\t * Destroys the title attribute of the element, storing its value in local\n\t * state so that it can be restored later (see `restoreTitleAttr`).\n\t *\n\t * @param {Element} el\n\t */\n\tfunction destroyTitleAttr( el ) {\n\t\tvar $el = $( el );\n\n\t\t// Has the user dwelled on a link? If we've already removed its title\n\t\t// attribute, then NOOP.\n\t\tif ( title ) {\n\t\t\treturn;\n\t\t}\n\n\t\ttitle = $el.attr( 'title' );\n\n\t\t$el.attr( 'title', '' );\n\t}\n\n\t/**\n\t * Restores the title attribute of the element.\n\t *\n\t * @param {Element} el\n\t */\n\tfunction restoreTitleAttr( el ) {\n\t\t$( el ).attr( 'title', title );\n\n\t\ttitle = undefined;\n\t}\n\n\treturn function ( prevState, state ) {\n\t\tvar hasPrevActiveLink = prevState && prevState.preview.activeLink;\n\n\t\tif ( !state.preview.enabled ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( hasPrevActiveLink ) {\n\n\t\t\t// Has the user dwelled on a link immediately after abandoning another\n\t\t\t// (remembering that the ABANDON_END action is delayed by\n\t\t\t// ~10e2 ms).\n\t\t\tif ( prevState.preview.activeLink !== state.preview.activeLink ) {\n\t\t\t\trestoreTitleAttr( prevState.preview.activeLink );\n\t\t\t}\n\t\t}\n\n\t\tif ( state.preview.activeLink ) {\n\t\t\tdestroyTitleAttr( state.preview.activeLink );\n\t\t}\n\t};\n}\n\n\n/***/ }),\n\n/***/ \"./src/changeListeners/render.js\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony export (immutable) */ __webpack_exports__[\"a\"] = render;\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__ui_renderer__ = __webpack_require__(\"./src/ui/renderer.js\");\n\n\n/**\n * Creates an instance of the render change listener.\n *\n * FIXME: Remove hard coupling with renderer, inject it as a parameter\n * * Wire it up in index.js\n * * Fix tests to remove require mocking\n *\n * @param {ext.popups.PreviewBehavior} previewBehavior\n * @return {ext.popups.ChangeListener}\n */\nfunction render( previewBehavior ) {\n\tvar preview;\n\n\treturn function ( prevState, state ) {\n\t\tif ( state.preview.shouldShow && !preview ) {\n\t\t\tpreview = __WEBPACK_IMPORTED_MODULE_0__ui_renderer__[\"b\" /* render */]( state.preview.fetchResponse );\n\t\t\tpreview.show(\n\t\t\t\tstate.preview.activeEvent,\n\t\t\t\tpreviewBehavior,\n\t\t\t\tstate.preview.activeToken\n\t\t\t\t);\n\t\t} else if ( !state.preview.shouldShow && preview ) {\n\t\t\tpreview.hide();\n\t\t\tpreview = undefined;\n\t\t}\n\t};\n}\n\n\n/***/ }),\n\n/***/ \"./src/changeListeners/settings.js\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony export (immutable) */ __webpack_exports__[\"a\"] = settings;\n/**\n * Creates an instance of the settings change listener.\n *\n * @param {Object} boundActions\n * @param {Object} render function that renders a jQuery el with the settings\n * @return {ext.popups.ChangeListener}\n */\nfunction settings( boundActions, render ) {\n\tvar settings;\n\n\treturn function ( prevState, state ) {\n\t\tif ( !prevState ) {\n\t\t\t// Nothing to do on initialization\n\t\t\treturn;\n\t\t}\n\n\t\t// Update global modal visibility\n\t\tif (\n\t\t\tprevState.settings.shouldShow === false &&\n\t\t\tstate.settings.shouldShow === true\n\t\t) {\n\t\t\t// Lazily instantiate the settings UI\n\t\t\tif ( !settings ) {\n\t\t\t\tsettings = render( boundActions );\n\t\t\t\tsettings.appendTo( document.body );\n\t\t\t}\n\n\t\t\t// Update the UI settings with the current settings\n\t\t\tsettings.setEnabled( state.preview.enabled );\n\n\t\t\tsettings.show();\n\t\t} else if (\n\t\t\tprevState.settings.shouldShow === true &&\n\t\t\tstate.settings.shouldShow === false\n\t\t) {\n\t\t\tsettings.hide();\n\t\t}\n\n\t\t// Update help visibility\n\t\tif ( prevState.settings.showHelp !== state.settings.showHelp ) {\n\t\t\tsettings.toggleHelp( state.settings.showHelp );\n\t\t}\n\t};\n}\n\n\n/***/ }),\n\n/***/ \"./src/changeListeners/statsv.js\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony export (immutable) */ __webpack_exports__[\"a\"] = statsv;\n/**\n * Creates an instance of the statsv change listener.\n *\n * The listener will log events to StatsD via the [the \"StatsD timers and\n * counters\" analytics event protocol][0].\n *\n * [0]: https://github.com/wikimedia/mediawiki-extensions-WikimediaEvents/blob/29c864a0/modules/ext.wikimediaEvents.statsd.js\n *\n * @param {Object} boundActions\n * @param {EventTracker} track\n * @return {ext.popups.ChangeListener}\n */\nfunction statsv( boundActions, track ) {\n\treturn function ( _, state ) {\n\t\tvar statsv = state.statsv;\n\n\t\tif ( statsv.action ) {\n\t\t\ttrack( statsv.action, statsv.data );\n\n\t\t\tboundActions.statsvLogged();\n\t\t}\n\t};\n}\n\n\n/***/ }),\n\n/***/ \"./src/changeListeners/syncUserSettings.js\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony export (immutable) */ __webpack_exports__[\"a\"] = syncUserSettings;\n/**\n * @module changeListeners/syncUserSettings\n */\n\n/**\n * Creates an instance of the user settings sync change listener.\n *\n * This change listener syncs certain parts of the state tree to user\n * settings when they change.\n *\n * Used for:\n *\n * * Enabled state: If the previews are enabled or disabled.\n * * Preview count: When the user dwells on a link for long enough that\n * a preview is shown, then their preview count will be incremented (see\n * `reducers/eventLogging.js`, and is persisted to local storage.\n *\n * @param {ext.popups.UserSettings} userSettings\n * @return {ext.popups.ChangeListener}\n */\nfunction syncUserSettings( userSettings ) {\n\n\treturn function ( prevState, state ) {\n\n\t\tsyncIfChanged(\n\t\t\tprevState, state, 'eventLogging', 'previewCount',\n\t\t\tuserSettings.setPreviewCount\n\t\t);\n\t\tsyncIfChanged(\n\t\t\tprevState, state, 'preview', 'enabled',\n\t\t\tuserSettings.setIsEnabled\n\t\t);\n\n\t};\n}\n\n/**\n * Given a state tree, reducer and property, safely return the value of the\n * property if the reducer and property exist\n * @param {Object} state tree\n * @param {String} reducer key to access on the state tree\n * @param {String} prop key to access on the reducer key of the state tree\n * @return {*}\n */\nfunction get( state, reducer, prop ) {\n\treturn state[ reducer ] && state[ reducer ][ prop ];\n}\n\n/**\n * Calls a sync function if the property prop on the property reducer on\n * the state trees has changed value.\n * @param {Object} prevState\n * @param {Object} state\n * @param {String} reducer key to access on the state tree\n * @param {String} prop key to access on the reducer key of the state tree\n * @param {Function} sync function to be called with the newest value if\n * changed\n */\nfunction syncIfChanged( prevState, state, reducer, prop, sync ) {\n\tvar current = get( state, reducer, prop );\n\tif ( prevState && ( get( prevState, reducer, prop ) !== current ) ) {\n\t\tsync( current );\n\t}\n}\n\n\n/***/ }),\n\n/***/ \"./src/constants.js\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"a\", function() { return BUCKETS; });\n/**\n * @module constants\n */\nvar $ = jQuery,\n\t// If bracketedDevicePixelRatio is not available default to 1 (in tests for\n\t// example)\n\tpixelRatio = $.bracketedDevicePixelRatio && $.bracketedDevicePixelRatio() || 1,\n\tBUCKETS = {\n\t\toff: 'off',\n\t\ton: 'on',\n\t\tcontrol: 'control'\n\t};\n\n\n\n/* harmony default export */ __webpack_exports__[\"b\"] = ({\n\tTHUMBNAIL_SIZE: 320 * pixelRatio,\n\tEXTRACT_LENGTH: 525\n});\n\n\n/***/ }),\n\n/***/ \"./src/counts.js\":\n/***/ (function(module, exports) {\n\n/**\n * @module counts\n */\n\n/**\n * Gets the count bucket for the number of edits a user has made.\n *\n * The buckets are defined as part of\n * [the Popups schema](https://meta.wikimedia.org/wiki/Schema:Popups).\n *\n * Extracted from `mw.popups.schemaPopups.getEditCountBucket`.\n *\n * @param {Number} count\n * @return {String}\n */\nexports.getEditCountBucket = function getEditCountBucket( count ) {\n\tvar bucket;\n\n\tif ( count === 0 ) {\n\t\tbucket = '0';\n\t} else if ( count >= 1 && count <= 4 ) {\n\t\tbucket = '1-4';\n\t} else if ( count >= 5 && count <= 99 ) {\n\t\tbucket = '5-99';\n\t} else if ( count >= 100 && count <= 999 ) {\n\t\tbucket = '100-999';\n\t} else if ( count >= 1000 ) {\n\t\tbucket = '1000+';\n\t}\n\n\treturn bucket + ' edits';\n};\n\n/**\n * Gets the count bucket for the number of previews a user has seen.\n *\n * If local storage isn't available - because the user has disabled it\n * or the browser doesn't support it - then then \"unknown\" is returned.\n *\n * The buckets are defined as part of\n * [the Popups schema](https://meta.wikimedia.org/wiki/Schema:Popups).\n *\n * Extracted from `mw.popups.getPreviewCountBucket`.\n *\n * @param {Number} count\n * @return {String}\n */\nexports.getPreviewCountBucket = function getPreviewCountBucket( count ) {\n\tvar bucket;\n\n\tif ( count === 0 ) {\n\t\tbucket = '0';\n\t} else if ( count >= 1 && count <= 4 ) {\n\t\tbucket = '1-4';\n\t} else if ( count >= 5 && count <= 20 ) {\n\t\tbucket = '5-20';\n\t} else if ( count >= 21 ) {\n\t\tbucket = '21+';\n\t}\n\n\treturn bucket !== undefined ? ( bucket + ' previews' ) : 'unknown';\n};\n\n\n/***/ }),\n\n/***/ \"./src/experiments.js\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony export (immutable) */ __webpack_exports__[\"a\"] = createExperiments;\n/**\n * @module experiments\n */\n\n/**\n * @interface Experiments\n *\n * @global\n */\n\n/**\n * Creates a helper wrapper for the MediaWiki-provided\n * `mw.experiments#getBucket` bucketing function.\n *\n * @param {mw.experiments} mwExperiments The `mw.experiments` singleton instance\n * @return {Experiments}\n */\nfunction createExperiments( mwExperiments ) {\n\treturn {\n\n\t\t/**\n\t\t * Gets whether something is true given a name and a token.\n\t\t *\n\t\t * @example\n\t\t * import createExperiments from './src/experiments';\n\t\t * const experiments = createExperiments( mw.experiments );\n\t\t * const isFooEnabled = experiments.weightedBoolean(\n\t\t * 'foo',\n\t\t * 10 / 100, // 10% of all unique tokens should have foo enabled.\n\t\t * token\n\t\t * );\n\t\t *\n\t\t * @function\n\t\t * @name Experiments#weightedBoolean\n\t\t * @param {String} name The name of the thing. Since this is used as the\n\t\t * name of the underlying experiment it should be unique to reduce the\n\t\t * likelihood of collisions with other enabled experiments\n\t\t * @param {Number} trueWeight A number between 0 and 1, representing the\n\t\t * probability of the thing being true\n\t\t * @param {String} token A token associated with the user for the duration\n\t\t * of the experiment\n\t\t * @return {Boolean}\n\t\t */\n\t\tweightedBoolean: function ( name, trueWeight, token ) {\n\t\t\treturn mwExperiments.getBucket( {\n\t\t\t\tenabled: true,\n\n\t\t\t\tname: name,\n\t\t\t\tbuckets: {\n\t\t\t\t\t'true': trueWeight,\n\t\t\t\t\t'false': 1 - trueWeight\n\t\t\t\t}\n\t\t\t}, token ) === 'true';\n\t\t}\n\t};\n}\n\n\n/***/ }),\n\n/***/ \"./src/formatter.js\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony export (immutable) */ __webpack_exports__[\"c\"] = formatPlainTextExtract;\n/* harmony export (immutable) */ __webpack_exports__[\"a\"] = removeTrailingEllipsis;\n/* harmony export (immutable) */ __webpack_exports__[\"b\"] = removeParentheticals;\nvar $ = jQuery,\n\tmw = window.mediaWiki;\n\n/**\n * Improves the plain text extracts\n * @param {String} plainTextExtract\n * @param {String} title\n * @returns {Array}\n */\nfunction formatPlainTextExtract( plainTextExtract, title ) {\n\tvar extract = plainTextExtract;\n\tif ( plainTextExtract === undefined ) {\n\t\treturn [];\n\t}\n\n\textract = removeParentheticals( extract );\n\textract = removeTrailingEllipsis( extract );\n\n\t// After cleaning the extract it may have been blanked\n\tif ( extract.length === 0 ) {\n\t\treturn [];\n\t}\n\n\textract = makeTitleInExtractBold( extract, title );\n\treturn extract;\n}\n\n/**\n * Converts the extract into a list of elements, which correspond to fragments\n * of the extract. Fragments that match the title verbatim are wrapped in a\n * `<b>` element.\n *\n * Using the bolded elements of the extract of the page directly is covered by\n * [T141651](https://phabricator.wikimedia.org/T141651).\n *\n * Extracted from `mw.popups.renderer.article.getProcessedElements`.\n *\n * @param {String} extract\n * @param {String} title\n * @return {Array} A set of HTML Elements\n */\nfunction makeTitleInExtractBold( extract, title ) {\n\tvar regExp, escapedTitle,\n\t\telements = [],\n\t\tboldIdentifier = '<bi-' + Math.random() + '>',\n\t\tsnip = '<snip-' + Math.random() + '>';\n\n\ttitle = title.replace( /\\s+/g, ' ' ).trim(); // Remove extra white spaces\n\tescapedTitle = mw.RegExp.escape( title ); // Escape RegExp elements\n\tregExp = new RegExp( '(^|\\\\s)(' + escapedTitle + ')(|$)', 'i' );\n\n\t// Remove text in parentheses along with the parentheses\n\textract = extract.replace( /\\s+/, ' ' ); // Remove extra white spaces\n\n\t// Make title bold in the extract text\n\t// As the extract is html escaped there can be no such string in it\n\t// Also, the title is escaped of RegExp elements thus can't have \"*\"\n\textract = extract.replace( regExp, '$1' + snip + boldIdentifier + '$2' + snip + '$3' );\n\textract = extract.split( snip );\n\n\t$.each( extract, function ( index, part ) {\n\t\tif ( part.indexOf( boldIdentifier ) === 0 ) {\n\t\t\telements.push( $( '<b>' ).text( part.substring( boldIdentifier.length ) ) );\n\t\t} else {\n\t\t\telements.push( document.createTextNode( part ) );\n\t\t}\n\t} );\n\n\treturn elements;\n}\n\n/**\n * Removes the trailing ellipsis from the extract, if it's there.\n *\n * This function was extracted from\n * `mw.popups.renderer.article#removeEllipsis`.\n *\n * @param {String} extract\n * @return {String}\n */\nfunction removeTrailingEllipsis( extract ) {\n\treturn extract.replace( /\\.\\.\\.$/, '' );\n}\n\n/**\n * Removes parentheticals from the extract.\n *\n * If the parenthesis are unbalanced or out of order, then the extract is\n * returned without further processing.\n *\n * This function was extracted from\n * `mw.popups.renderer.article#removeParensFromText`.\n *\n * @param {String} extract\n * @return {String}\n */\nfunction removeParentheticals( extract ) {\n\tvar\n\t\tch,\n\t\tresult = '',\n\t\tlevel = 0,\n\t\ti = 0;\n\n\tfor ( i; i < extract.length; i++ ) {\n\t\tch = extract.charAt( i );\n\n\t\tif ( ch === ')' && level === 0 ) {\n\t\t\treturn extract;\n\t\t}\n\t\tif ( ch === '(' ) {\n\t\t\tlevel++;\n\t\t\tcontinue;\n\t\t} else if ( ch === ')' ) {\n\t\t\tlevel--;\n\t\t\tcontinue;\n\t\t}\n\t\tif ( level === 0 ) {\n\t\t\t// Remove leading spaces before brackets\n\t\t\tif ( ch === ' ' && extract.charAt( i + 1 ) === '(' ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tresult += ch;\n\t\t}\n\t}\n\n\treturn ( level === 0 ) ? result : extract;\n}\n\n\n/***/ }),\n\n/***/ \"./src/gateway/index.js\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony export (immutable) */ __webpack_exports__[\"a\"] = createGateway;\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__constants__ = __webpack_require__(\"./src/constants.js\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__mediawiki__ = __webpack_require__(\"./src/gateway/mediawiki.js\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__rest__ = __webpack_require__(\"./src/gateway/rest.js\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__restFormatters__ = __webpack_require__(\"./src/gateway/restFormatters.js\");\n\n\n\n\n\nvar mw = mediaWiki,\n\t$ = jQuery;\n\n// Note that this interface definition is in the global scope.\n/**\n * The interface implemented by all preview gateways.\n *\n * @interface Gateway\n */\n\n/**\n * Fetches a preview for a page.\n *\n * If the underlying request is successful and contains data about the page,\n * then the resulting promise will resolve. If not, then it will reject.\n *\n * @function\n * @name Gateway#getPageSummary\n * @param {String} title The title of the page\n * @returns {jQuery.Promise<PreviewModel>}\n */\n\n/**\n * Creates a gateway with sensible values for the dependencies.\n *\n * @param {mw.Map} config\n * @return {Gateway}\n */\nfunction createGateway( config ) {\n\tswitch ( config.get( 'wgPopupsGateway' ) ) {\n\t\tcase 'mwApiPlain':\n\t\t\treturn __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__mediawiki__[\"a\" /* default */])( new mw.Api(), __WEBPACK_IMPORTED_MODULE_0__constants__[\"b\" /* default */] );\n\t\tcase 'restbasePlain':\n\t\t\treturn __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_2__rest__[\"a\" /* default */])( $.ajax, __WEBPACK_IMPORTED_MODULE_0__constants__[\"b\" /* default */], __WEBPACK_IMPORTED_MODULE_3__restFormatters__[\"a\" /* parsePlainTextResponse */] );\n\t\tcase 'restbaseHTML':\n\t\t\treturn __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_2__rest__[\"a\" /* default */])( $.ajax, __WEBPACK_IMPORTED_MODULE_0__constants__[\"b\" /* default */], __WEBPACK_IMPORTED_MODULE_3__restFormatters__[\"b\" /* parseHTMLResponse */] );\n\t\tdefault:\n\t\t\tthrow new Error( 'Unknown gateway' );\n\t}\n}\n\n\n/***/ }),\n\n/***/ \"./src/gateway/mediawiki.js\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony export (immutable) */ __webpack_exports__[\"a\"] = createMediaWikiApiGateway;\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__preview_model__ = __webpack_require__(\"./src/preview/model.js\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__formatter__ = __webpack_require__(\"./src/formatter.js\");\n/**\n * @module gateway/mediawiki\n */\n\n/**\n * @interface MediaWikiGateway\n * @extends Gateway\n *\n * @global\n */\n\n\n\n\n// Public and private cache lifetime (5 minutes)\n//\n// FIXME: Move this to src/constants.js.\nvar CACHE_LIFETIME = 300,\n\t$ = jQuery;\n\n/**\n * Creates an instance of the MediaWiki API gateway.\n *\n * @param {mw.Api} api\n * @param {Object} config Configuration that affects the major behavior of the\n * gateway.\n * @param {Number} config.THUMBNAIL_SIZE The length of the major dimension of\n * the thumbnail.\n * @param {Number} config.EXTRACT_LENGTH The maximum length, in characters,\n * of the extract.\n * @returns {MediaWikiGateway}\n */\nfunction createMediaWikiApiGateway( api, config ) {\n\n\t/**\n\t * Fetches page data from the API.\n\t *\n\t * @function\n\t * @name MediaWikiGateway#fetch\n\t * @param {String} title\n\t * @return {jQuery.Promise}\n\t */\n\tfunction fetch( title ) {\n\t\treturn api.get( {\n\t\t\taction: 'query',\n\t\t\tprop: 'info|extracts|pageimages|revisions|info',\n\t\t\tformatversion: 2,\n\t\t\tredirects: true,\n\t\t\texintro: true,\n\t\t\texchars: config.EXTRACT_LENGTH,\n\n\t\t\t// There is an added geometric limit on .mwe-popups-extract\n\t\t\t// so that text does not overflow from the card.\n\t\t\texplaintext: true,\n\n\t\t\tpiprop: 'thumbnail',\n\t\t\tpithumbsize: config.THUMBNAIL_SIZE,\n\t\t\tpilicense: 'any',\n\t\t\trvprop: 'timestamp',\n\t\t\tinprop: 'url',\n\t\t\ttitles: title,\n\t\t\tsmaxage: CACHE_LIFETIME,\n\t\t\tmaxage: CACHE_LIFETIME,\n\t\t\tuselang: 'content'\n\t\t}, {\n\t\t\theaders: {\n\t\t\t\t'X-Analytics': 'preview=1'\n\t\t\t}\n\t\t} );\n\t}\n\n\tfunction getPageSummary( title ) {\n\t\treturn fetch( title )\n\t\t\t.then( extractPageFromResponse )\n\t\t\t.then( formatPlainTextExtract )\n\t\t\t.then( convertPageToModel );\n\t}\n\n\treturn {\n\t\tfetch: fetch,\n\t\textractPageFromResponse: extractPageFromResponse,\n\t\tconvertPageToModel: convertPageToModel,\n\t\tgetPageSummary: getPageSummary,\n\t\tformatPlainTextExtract: formatPlainTextExtract\n\t};\n}\n\n/**\n * Extracts page data from the API response.\n *\n * @function\n * @name MediaWikiGateway#extractPageFromResponse\n * @param {Object} data The response\n * @throws {Error} If the response is empty or doesn't contain data about the\n * page\n * @returns {Object}\n */\nfunction extractPageFromResponse( data ) {\n\tif (\n\t\tdata.query &&\n\t\tdata.query.pages &&\n\t\tdata.query.pages.length\n\t) {\n\t\treturn data.query.pages[ 0 ];\n\t}\n\n\tthrow new Error( 'API response `query.pages` is empty.' );\n}\n\n/**\n * Make plain text nicer by applying formatter.\n *\n * @function\n * @name MediaWikiGateway#formatPlainTextExtract\n * @param {Object} data The response\n * @returns {Object}\n */\nfunction formatPlainTextExtract( data ) {\n\tvar result = $.extend( {}, data );\n\tresult.extract = __WEBPACK_IMPORTED_MODULE_1__formatter__[\"c\" /* formatPlainTextExtract */]( data.extract, data.title );\n\treturn result;\n}\n\n/**\n * Converts the API response to a preview model.\n *\n * @function\n * @name MediaWikiGateway#convertPageToModel\n * @param {Object} page\n * @returns {PreviewModel}\n */\nfunction convertPageToModel( page ) {\n\treturn __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__preview_model__[\"b\" /* createModel */])(\n\t\tpage.title,\n\t\tpage.canonicalurl,\n\t\tpage.pagelanguagehtmlcode,\n\t\tpage.pagelanguagedir,\n\t\tpage.extract,\n\t\tpage.thumbnail\n\t);\n}\n\n\n/***/ }),\n\n/***/ \"./src/gateway/rest.js\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony export (immutable) */ __webpack_exports__[\"a\"] = createRESTBaseGateway;\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__preview_model__ = __webpack_require__(\"./src/preview/model.js\");\n/**\n * @module gateway/rest\n */\n\n\n\nvar RESTBASE_ENDPOINT = '/api/rest_v1/page/summary/',\n\tRESTBASE_PROFILE = 'https://www.mediawiki.org/wiki/Specs/Summary/1.2.0',\n\tmw = window.mediaWiki,\n\t$ = jQuery;\n/**\n * @interface RESTBaseGateway\n * @extends Gateway\n *\n * @global\n */\n\n/**\n * Creates an instance of the RESTBase gateway.\n *\n * This gateway differs from the {@link MediaWikiGateway MediaWiki gateway} in\n * that it fetches page data from [the RESTBase page summary endpoint][0].\n *\n * [0]: https://en.wikipedia.org/api/rest_v1/#!/Page_content/get_page_summary_title\n *\n * @param {Function} ajax A function with the same signature as `jQuery.ajax`\n * @param {Object} config Configuration that affects the major behavior of the\n * gateway.\n * @param {Number} config.THUMBNAIL_SIZE The length of the major dimension of\n * the thumbnail.\n * @param {Function} extractParser A function that takes response and returns parsed extract\n * @returns {RESTBaseGateway}\n */\nfunction createRESTBaseGateway( ajax, config, extractParser ) {\n\n\t/**\n\t * Fetches page data from [the RESTBase page summary endpoint][0].\n\t *\n\t * [0]: https://en.wikipedia.org/api/rest_v1/#!/Page_content/get_page_summary_title\n\t *\n\t * @function\n\t * @name MediaWikiGateway#fetch\n\t * @param {String} title\n\t * @return {jQuery.Promise}\n\t */\n\tfunction fetch( title ) {\n\t\treturn ajax( {\n\t\t\turl: RESTBASE_ENDPOINT + encodeURIComponent( title ),\n\t\t\theaders: {\n\t\t\t\tAccept: 'application/json; charset=utf-8; ' +\n\t\t\t\t\t'profile=\"' + RESTBASE_PROFILE + '\"'\n\t\t\t}\n\t\t} );\n\t}\n\n\tfunction getPageSummary( title ) {\n\t\tvar result = $.Deferred();\n\n\t\tfetch( title )\n\t\t\t.then(\n\t\t\t\tfunction ( page ) {\n\t\t\t\t\tresult.resolve(\n\t\t\t\t\t\tconvertPageToModel( page, config.THUMBNAIL_SIZE, extractParser ) );\n\t\t\t\t},\n\t\t\t\tfunction ( jqXHR ) {\n\t\t\t\t\tif ( jqXHR.status === 404 ) {\n\n\t\t\t\t\t\tresult.resolve(\n\t\t\t\t\t\t\t__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__preview_model__[\"a\" /* createNullModel */])( title )\n\t\t\t\t\t\t);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresult.reject();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t);\n\n\t\treturn result.promise();\n\t}\n\n\treturn {\n\t\tfetch: fetch,\n\t\tconvertPageToModel: convertPageToModel,\n\t\tgetPageSummary: getPageSummary\n\t};\n}\n\n/**\n * Resizes the thumbnail to the requested width, preserving its aspect ratio.\n *\n * The requested width is limited to that of the original image unless the image\n * is an SVG, which can be scaled infinitely.\n *\n * This function is only intended to mangle the pretty thumbnail URLs used on\n * Wikimedia Commons. Once [an official thumb API](https://phabricator.wikimedia.org/T66214)\n * is fully specified and implemented, this function can be made more general.\n *\n * @param {Object} thumbnail The thumbnail image\n * @param {Object} original The original image\n * @param {Number} thumbSize The requested size\n * @returns {Object}\n */\nfunction generateThumbnailData( thumbnail, original, thumbSize ) {\n\tvar parts = thumbnail.source.split( '/' ),\n\t\tlastPart = parts[ parts.length - 1 ],\n\t\tfilename,\n\t\twidth,\n\t\theight;\n\n\t// The last part, the thumbnail's full filename, is in the following form:\n\t// ${width}px-${filename}.${extension}. Splitting the thumbnail's filename\n\t// makes this function resilient to the thumbnail not having the same\n\t// extension as the original image, which is definitely the case for SVG's\n\t// where the thumbnail's extension is .svg.png.\n\tfilename = lastPart.substr( lastPart.indexOf( 'px-' ) + 3 );\n\n\t// Scale the thumbnail's largest dimension.\n\tif ( thumbnail.width > thumbnail.height ) {\n\t\twidth = thumbSize;\n\t\theight = Math.floor( ( thumbSize / thumbnail.width ) * thumbnail.height );\n\t} else {\n\t\twidth = Math.floor( ( thumbSize / thumbnail.height ) * thumbnail.width );\n\t\theight = thumbSize;\n\t}\n\n\t// If the image isn't an SVG, then it shouldn't be scaled past its original\n\t// dimensions.\n\tif ( width >= original.width && filename.indexOf( '.svg' ) === -1 ) {\n\t\treturn original;\n\t}\n\n\tparts[ parts.length - 1 ] = width + 'px-' + filename;\n\n\treturn {\n\t\tsource: parts.join( '/' ),\n\t\twidth: width,\n\t\theight: height\n\t};\n}\n\n/**\n * Converts the API response to a preview model.\n *\n * @function\n * @name RESTBaseGateway#convertPageToModel\n * @param {Object} page\n * @param {Number} thumbSize\n * @param {Function} extractParser\n * @returns {PreviewModel}\n */\nfunction convertPageToModel( page, thumbSize, extractParser ) {\n\treturn __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__preview_model__[\"b\" /* createModel */])(\n\t\tpage.title,\n\t\tnew mw.Title( page.title ).getUrl(),\n\t\tpage.lang,\n\t\tpage.dir,\n\t\textractParser( page ),\n\t\tpage.thumbnail ? generateThumbnailData( page.thumbnail, page.originalimage, thumbSize ) : undefined\n\t);\n}\n\n\n/***/ }),\n\n/***/ \"./src/gateway/restFormatters.js\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony export (immutable) */ __webpack_exports__[\"b\"] = parseHTMLResponse;\n/* harmony export (immutable) */ __webpack_exports__[\"a\"] = parsePlainTextResponse;\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__formatter__ = __webpack_require__(\"./src/formatter.js\");\n\n\n/**\n * Prepare extract\n * @param {Object} page Rest response\n * @returns {Array} An array of DOM Elements\n */\nfunction parseHTMLResponse( page ) {\n\tvar extract = page.extract_html;\n\textract = __WEBPACK_IMPORTED_MODULE_0__formatter__[\"a\" /* removeTrailingEllipsis */]( extract );\n\textract = __WEBPACK_IMPORTED_MODULE_0__formatter__[\"b\" /* removeParentheticals */]( extract );\n\n\treturn extract.length === 0 ? [] : $.parseHTML( extract );\n}\n\n/**\n * Prepare extract\n * @param {Object} page Rest response\n * @returns {Array} An array of DOM Elements\n */\nfunction parsePlainTextResponse( page ) {\n\treturn __WEBPACK_IMPORTED_MODULE_0__formatter__[\"c\" /* formatPlainTextExtract */]( page.extract, page.title );\n}\n\n\n/***/ }),\n\n/***/ \"./src/getUserBucket.js\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/**\n * What is the bucket for the given user given the enabled sampling rate?\n *\n * @param {mw.experiments} experiments The `mw.experiments` singleton instance\n * @param {Number} experimentGroupSize [0,1] of users of which should be subjected to an\n * A/B test. The remaining users will be put in the 'off' bucket.\n * @param {string} sessionId a unique session token\n *\n * @return {string} bucket that the user belongs to (off/control/on)\n */\nfunction getUserBucket( experiments, experimentGroupSize, sessionId ) {\n\tvar control = experimentGroupSize / 2;\n\tif ( !experimentGroupSize ) {\n\t\t// no users are subject to experiment\n\t\treturn 'on';\n\t}\n\n\treturn experiments.getBucket( {\n\t\tname: 'ext.Popups.visibility',\n\t\tenabled: true,\n\t\tbuckets: {\n\t\t\toff: 1 - experimentGroupSize,\n\t\t\tcontrol: control,\n\t\t\ton: control\n\t\t}\n\t}, sessionId );\n}\n\n/* harmony default export */ __webpack_exports__[\"a\"] = (getUserBucket);\n\n\n/***/ }),\n\n/***/ \"./src/index.js\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\nObject.defineProperty(__webpack_exports__, \"__esModule\", { value: true });\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_redux__ = __webpack_require__(\"./node_modules/redux/dist/redux.min.js\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_redux___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_redux__);\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_redux_thunk__ = __webpack_require__(\"./node_modules/redux-thunk/dist/redux-thunk.min.js\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_redux_thunk___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1_redux_thunk__);\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__gateway__ = __webpack_require__(\"./src/gateway/index.js\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__userSettings__ = __webpack_require__(\"./src/userSettings.js\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__previewBehavior__ = __webpack_require__(\"./src/previewBehavior.js\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__ui_settingsDialog__ = __webpack_require__(\"./src/ui/settingsDialog.js\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__changeListener__ = __webpack_require__(\"./src/changeListener.js\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_7__isEnabled__ = __webpack_require__(\"./src/isEnabled.js\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_8__title__ = __webpack_require__(\"./src/title.js\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_9__ui_renderer__ = __webpack_require__(\"./src/ui/renderer.js\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_10__experiments__ = __webpack_require__(\"./src/experiments.js\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_11__instrumentation_statsv__ = __webpack_require__(\"./src/instrumentation/statsv.js\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_12__instrumentation_eventLogging__ = __webpack_require__(\"./src/instrumentation/eventLogging.js\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_13__changeListeners__ = __webpack_require__(\"./src/changeListeners/index.js\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_14__actions__ = __webpack_require__(\"./src/actions.js\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_15__reducers__ = __webpack_require__(\"./src/reducers/index.js\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_16__integrations_mwpopups__ = __webpack_require__(\"./src/integrations/mwpopups.js\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_17__getUserBucket__ = __webpack_require__(\"./src/getUserBucket.js\");\n/**\n * @module popups\n */\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nvar mw = mediaWiki,\n\t$ = jQuery,\n\n\tBLACKLISTED_LINKS = [\n\t\t'.extiw',\n\t\t'.image',\n\t\t'.new',\n\t\t'.internal',\n\t\t'.external',\n\t\t'.oo-ui-buttonedElement-button',\n\t\t'.cancelLink a'\n\t];\n\n/**\n * @typedef {Function} EventTracker\n *\n * An analytics event tracker, i.e. `mw.track`.\n *\n * @param {String} topic\n * @param {Object} data\n *\n * @global\n */\n\n/**\n * Gets the appropriate analytics event tracker for logging metrics to StatsD\n * via [the \"StatsD timers and counters\" analytics event protocol][0].\n *\n * If logging metrics to StatsD is enabled for the duration of the user's\n * session, then the appriopriate function is `mw.track`; otherwise it's\n * `$.noop`.\n *\n * [0]: https://github.com/wikimedia/mediawiki-extensions-WikimediaEvents/blob/29c864a0/modules/ext.wikimediaEvents.statsd.js\n *\n * @param {Object} user\n * @param {Object} config\n * @param {Experiments} experiments\n * @return {EventTracker}\n */\nfunction getStatsvTracker( user, config, experiments ) {\n\treturn __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_11__instrumentation_statsv__[\"a\" /* isEnabled */])( user, config, experiments ) ? mw.track : $.noop;\n}\n\n/**\n * Gets the appropriate analytics event tracker for logging EventLogging events\n * via [the \"EventLogging subscriber\" analytics event protocol][0].\n *\n * If logging EventLogging events is enabled for the duration of the user's\n * session, then the appriopriate function is `mw.track`; otherwise it's\n * `$.noop`.\n *\n * [0]: https://github.com/wikimedia/mediawiki-extensions-EventLogging/blob/d1409759/modules/ext.eventLogging.subscriber.js\n *\n * @param {Object} user\n * @param {Object} config\n * @param {String} bucket for user\n * @param {Window} window\n * @return {EventTracker}\n */\nfunction getEventLoggingTracker( user, config, bucket, window ) {\n\treturn __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_12__instrumentation_eventLogging__[\"a\" /* isEnabled */])(\n\t\tuser,\n\t\tconfig,\n\t\tbucket,\n\t\twindow\n\t) ? mw.track : $.noop;\n}\n\n/**\n * Subscribes the registered change listeners to the\n * [store](http://redux.js.org/docs/api/Store.html#store).\n *\n * @param {Redux.Store} store\n * @param {Object} actions\n * @param {UserSettings} userSettings\n * @param {Function} settingsDialog\n * @param {PreviewBehavior} previewBehavior\n * @param {EventTracker} statsvTracker\n * @param {EventTracker} eventLoggingTracker\n */\nfunction registerChangeListeners( store, actions, userSettings, settingsDialog, previewBehavior, statsvTracker, eventLoggingTracker ) {\n\t__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_6__changeListener__[\"a\" /* default */])( store, __WEBPACK_IMPORTED_MODULE_13__changeListeners__[\"a\" /* default */].footerLink( actions ) );\n\t__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_6__changeListener__[\"a\" /* default */])( store, __WEBPACK_IMPORTED_MODULE_13__changeListeners__[\"a\" /* default */].linkTitle() );\n\t__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_6__changeListener__[\"a\" /* default */])( store, __WEBPACK_IMPORTED_MODULE_13__changeListeners__[\"a\" /* default */].render( previewBehavior ) );\n\t__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_6__changeListener__[\"a\" /* default */])( store, __WEBPACK_IMPORTED_MODULE_13__changeListeners__[\"a\" /* default */].statsv( actions, statsvTracker ) );\n\t__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_6__changeListener__[\"a\" /* default */])( store, __WEBPACK_IMPORTED_MODULE_13__changeListeners__[\"a\" /* default */].syncUserSettings( userSettings ) );\n\t__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_6__changeListener__[\"a\" /* default */])( store, __WEBPACK_IMPORTED_MODULE_13__changeListeners__[\"a\" /* default */].settings( actions, settingsDialog ) );\n\t__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_6__changeListener__[\"a\" /* default */])( store, __WEBPACK_IMPORTED_MODULE_13__changeListeners__[\"a\" /* default */].eventLogging( actions, eventLoggingTracker ) );\n}\n\n/*\n * Initialize the application by:\n * 1. Creating the state store\n * 2. Binding the actions to such store\n * 3. Trigger the boot action to bootstrap the system\n * 4. When the page content is ready:\n * - Process the eligible links for page previews\n * - Initialize the renderer\n * - Bind hover and click events to the eligible links to trigger actions\n */\nmw.requestIdleCallback( function () {\n\tvar compose = __WEBPACK_IMPORTED_MODULE_0_redux__[\"compose\"],\n\t\tuserBucket,\n\t\tstore,\n\t\tboundActions,\n\n\t\t// So-called \"services\".\n\t\tgenerateToken = mw.user.generateRandomSessionId,\n\t\tgateway = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_2__gateway__[\"a\" /* default */])( mw.config ),\n\t\tuserSettings,\n\t\tsettingsDialog,\n\t\texperiments,\n\t\tstatsvTracker,\n\t\teventLoggingTracker,\n\t\tisEnabled,\n\t\tpreviewBehavior;\n\n\tuserBucket = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_17__getUserBucket__[\"a\" /* default */])( mw.experiments, mw.config.get( 'wgPopupsAnonsExperimentalGroupSize' ),\n\t\tmw.user.sessionId() );\n\tuserSettings = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_3__userSettings__[\"a\" /* default */])( mw.storage );\n\tsettingsDialog = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_5__ui_settingsDialog__[\"a\" /* default */])();\n\texperiments = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_10__experiments__[\"a\" /* default */])( mw.experiments );\n\tstatsvTracker = getStatsvTracker( mw.user, mw.config, experiments );\n\teventLoggingTracker = getEventLoggingTracker(\n\t\tmw.user,\n\t\tmw.config,\n\t\tuserBucket,\n\t\twindow\n\t);\n\n\tisEnabled = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_7__isEnabled__[\"a\" /* default */])( mw.user, userSettings, mw.config, userBucket );\n\n\t// If debug mode is enabled, then enable Redux DevTools.\n\tif ( mw.config.get( 'debug' ) === true ) {\n\t\t// eslint-disable-next-line no-underscore-dangle\n\t\tcompose = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;\n\t}\n\n\tstore = __WEBPACK_IMPORTED_MODULE_0_redux__[\"createStore\"](\n\t\t__WEBPACK_IMPORTED_MODULE_0_redux__[\"combineReducers\"]( __WEBPACK_IMPORTED_MODULE_15__reducers__[\"a\" /* default */] ),\n\t\tcompose( __WEBPACK_IMPORTED_MODULE_0_redux__[\"applyMiddleware\"](\n\t\t\t__WEBPACK_IMPORTED_MODULE_1_redux_thunk__[\"default\"]\n\t\t) )\n\t);\n\tboundActions = __WEBPACK_IMPORTED_MODULE_0_redux__[\"bindActionCreators\"]( __WEBPACK_IMPORTED_MODULE_14__actions__, store.dispatch );\n\n\tpreviewBehavior = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_4__previewBehavior__[\"a\" /* default */])( mw.config, mw.user, boundActions );\n\n\tregisterChangeListeners(\n\t\tstore, boundActions, userSettings, settingsDialog,\n\t\tpreviewBehavior, statsvTracker, eventLoggingTracker\n\t);\n\n\tboundActions.boot(\n\t\tisEnabled,\n\t\tmw.user,\n\t\tuserSettings,\n\t\tgenerateToken,\n\t\tmw.config\n\t);\n\n\t/*\n\t * Register external interface exposing popups internals so that other\n\t * extensions can query it (T171287)\n\t */\n\tmw.popups = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_16__integrations_mwpopups__[\"a\" /* default */])( store );\n\n\tmw.hook( 'wikipage.content' ).add( function ( $container ) {\n\t\tvar invalidLinksSelector = BLACKLISTED_LINKS.join( ', ' ),\n\t\t\tvalidLinkSelector = 'a[href][title]:not(' + invalidLinksSelector + ')';\n\n\t\t__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_9__ui_renderer__[\"a\" /* init */])();\n\n\t\t$container\n\t\t\t.on( 'mouseover keyup', validLinkSelector, function ( event ) {\n\t\t\t\tvar mwTitle = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_8__title__[\"a\" /* fromElement */])( this, mw.config );\n\n\t\t\t\tif ( mwTitle ) {\n\t\t\t\t\tboundActions.linkDwell( mwTitle, this, event, gateway, generateToken );\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.on( 'mouseout blur', validLinkSelector, function () {\n\t\t\t\tvar mwTitle = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_8__title__[\"a\" /* fromElement */])( this, mw.config );\n\n\t\t\t\tif ( mwTitle ) {\n\t\t\t\t\tboundActions.abandon( this );\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.on( 'click', validLinkSelector, function () {\n\t\t\t\tvar mwTitle = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_8__title__[\"a\" /* fromElement */])( this, mw.config );\n\n\t\t\t\tif ( mwTitle ) {\n\t\t\t\t\tboundActions.linkClick( this );\n\t\t\t\t}\n\t\t\t} );\n\n\t} );\n} );\n\nwindow.Redux = __WEBPACK_IMPORTED_MODULE_0_redux__;\nwindow.ReduxThunk = __WEBPACK_IMPORTED_MODULE_1_redux_thunk__;\n\n\n/***/ }),\n\n/***/ \"./src/instrumentation/eventLogging.js\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony export (immutable) */ __webpack_exports__[\"a\"] = isEnabled;\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__constants__ = __webpack_require__(\"./src/constants.js\");\n/**\n * @module instrumentation/eventLogging\n */\n\n\n/**\n * Gets whether EventLogging logging is enabled for the duration of the user's\n * session.\n * If wgPopupsEventLogging is false this will return false unless debug=true has\n * been enabled.\n * If an experiment is being run (ie. wgPopupsAnonsExperimentalGroupSize has been\n * defined) then event logging will only be enabled for those in the `on` or `control`\n * groups.\n * However, if the UA doesn't support [the Beacon API][1], then bucketing is\n * disabled.\n *\n * [1]: https://w3c.github.io/beacon/\n *\n * @param {mw.user} user The `mw.user` singleton instance\n * @param {mw.Map} config The `mw.config` singleton instance\n * @param {String} bucket that the user is in (see constants.js)\n * @param {Window} window\n * @return {Boolean}\n */\nfunction isEnabled( user, config, bucket, window ) {\n\t// if debug mode is on, always enable event logging. @see T168847\n\tif ( config.get( 'debug' ) === true ) {\n\t\treturn true;\n\t}\n\n\tif ( !config.get( 'wgPopupsEventLogging' ) ) {\n\t\treturn false;\n\t}\n\n\tif (\n\t\t!window.navigator ||\n\t\t!$.isFunction( window.navigator.sendBeacon )\n\t) {\n\t\treturn false;\n\t}\n\n\treturn user.isAnon() && bucket !== __WEBPACK_IMPORTED_MODULE_0__constants__[\"a\" /* BUCKETS */].off;\n}\n\n\n/***/ }),\n\n/***/ \"./src/instrumentation/statsv.js\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony export (immutable) */ __webpack_exports__[\"a\"] = isEnabled;\n/**\n * @module instrumentation/statsv\n */\n\n/**\n * Gets whether Graphite logging (via [the statsv HTTP endpoint][0]) is enabled\n * for the duration of the user's session. The bucketing rate is controlled by\n * `wgPopupsStatsvSamplingRate`.\n *\n * [0]: https://wikitech.wikimedia.org/wiki/Graphite#statsv\n *\n * @param {mw.user} user The `mw.user` singleton instance\n * @param {mw.Map} config The `mw.config` singleton instance\n * @param {Experiments} experiments\n * @returns {Boolean}\n */\nfunction isEnabled( user, config, experiments ) {\n\tvar bucketingRate = config.get( 'wgPopupsStatsvSamplingRate', 0 );\n\n\treturn experiments.weightedBoolean(\n\t\t'ext.Popups.statsv',\n\t\tbucketingRate,\n\t\tuser.sessionId()\n\t);\n}\n\n\n/***/ }),\n\n/***/ \"./src/integrations/mwpopups.js\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony export (immutable) */ __webpack_exports__[\"a\"] = createMwPopups;\n/**\n * @module MediaWiki-Popups Integration\n */\n\n/**\n * This function provides a mw.popups object which can be used by 3rd party\n * to interact with Popups. Currently it allows only to read isEnabled flag.\n *\n * @param {Redux.Store} store Popups store\n * @return {Object} external Popups interface\n */\nfunction createMwPopups( store ) {\n\treturn {\n\t\tisEnabled: function isEnabled() {\n\t\t\treturn store.getState().preview.enabled;\n\t\t}\n\t};\n\n}\n\n\n/***/ }),\n\n/***/ \"./src/isEnabled.js\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony export (immutable) */ __webpack_exports__[\"a\"] = isEnabled;\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__constants__ = __webpack_require__(\"./src/constants.js\");\n/**\n * @module isEnabled\n */\n\n\n/**\n * Given the global state of the application, creates a function that gets\n * whether or not the user should have Page Previews enabled.\n *\n * Page Previews is disabled when the Navigation Popups gadget is enabled.\n *\n * If Page Previews is configured as a beta feature (see\n * `$wgPopupsBetaFeature`), the user must be logged in and have enabled the\n * beta feature in order to see previews. Logged out users won't be able\n * to see the feature.\n *\n * If Page Previews is configured as a user preference, then the user must\n * either be logged in and have enabled the preference or be logged out and have\n * not disabled previews via the settings modal. Logged out users who have not\n * disabled or enabled the previews via the settings modal will be subject to\n * wgPopupsAnonsExperimentalGroupSize if defined.\n *\n * @param {mw.user} user The `mw.user` singleton instance\n * @param {Object} userSettings An object returned by `userSettings.js`\n * @param {mw.Map} config\n * @param {String} bucket the user belongs to (off, on or control)\n *\n * @return {Boolean}\n */\nfunction isEnabled( user, userSettings, config, bucket ) {\n\tif ( config.get( 'wgPopupsConflictsWithNavPopupGadget' ) ) {\n\t\treturn false;\n\t}\n\n\tif ( !user.isAnon() ) {\n\t\treturn config.get( 'wgPopupsShouldSendModuleToUser' );\n\t}\n\n\tif ( config.get( 'wgPopupsBetaFeature' ) ) {\n\t\treturn false;\n\t}\n\n\tif ( !userSettings.hasIsEnabled() ) {\n\t\treturn bucket === __WEBPACK_IMPORTED_MODULE_0__constants__[\"a\" /* BUCKETS */].on;\n\t}\n\n\treturn userSettings.getIsEnabled();\n}\n\n\n/***/ }),\n\n/***/ \"./src/preview/model.js\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* unused harmony export TYPE_GENERIC */\n/* unused harmony export TYPE_PAGE */\n/* harmony export (immutable) */ __webpack_exports__[\"b\"] = createModel;\n/* harmony export (immutable) */ __webpack_exports__[\"a\"] = createNullModel;\n/**\n * @module preview/model\n */\n\n/**\n * @constant {String}\n */\nvar TYPE_GENERIC = 'generic';\n\n/**\n * @constant {String}\n */\nvar TYPE_PAGE = 'page'; // eslint-disable-line one-var\n\n/**\n * @typedef {Object} PreviewModel\n * @property {String} title\n * @property {String} url The canonical URL of the page being previewed\n * @property {String} languageCode\n * @property {String} languageDirection Either \"ltr\" or \"rtl\"\n * @property {?Array} extract `undefined` if the extract isn't\n * viable, e.g. if it's empty after having ellipsis and parentheticals\n * removed\n * @property {String} type Either \"extract\" or \"generic\"\n * @property {?Object} thumbnail\n *\n * @global\n */\n\n/**\n * Creates a preview model.\n *\n * @param {String} title\n * @param {String} url The canonical URL of the page being previewed\n * @param {String} languageCode\n * @param {String} languageDirection Either \"ltr\" or \"rtl\"\n * @param {?Array} extract\n * @param {?Object} thumbnail\n * @return {PreviewModel}\n */\nfunction createModel(\n\ttitle,\n\turl,\n\tlanguageCode,\n\tlanguageDirection,\n\textract,\n\tthumbnail\n) {\n\tvar processedExtract = processExtract( extract );\n\n\treturn {\n\t\ttitle: title,\n\t\turl: url,\n\t\tlanguageCode: languageCode,\n\t\tlanguageDirection: languageDirection,\n\t\textract: processedExtract,\n\t\ttype: processedExtract === undefined ? TYPE_GENERIC : TYPE_PAGE,\n\t\tthumbnail: thumbnail\n\t};\n}\n\n/**\n * Creates an empty preview model.\n *\n * @param {String} title\n * @return {PreviewModel}\n */\nfunction createNullModel( title ) {\n\treturn createModel( title, '', '', '', [], '' );\n}\n\n/**\n * Processes the extract returned by the TextExtracts MediaWiki API query\n * module.\n *\n * If the extract is `undefined`, `null`, or empty, then `undefined` is\n * returned.\n *\n * @param {Array|undefined|null} extract\n * @return {Array|undefined} Array when extract is an not empty array, undefined otherwise\n */\nfunction processExtract( extract ) {\n\tif ( extract === undefined || extract === null || extract.length === 0 ) {\n\t\treturn undefined;\n\t}\n\treturn extract;\n}\n\n\n/***/ }),\n\n/***/ \"./src/previewBehavior.js\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony export (immutable) */ __webpack_exports__[\"a\"] = createPreviewBehavior;\n/**\n * @module previewBehaviour\n */\n\nvar mw = window.mediaWiki,\n\t$ = jQuery;\n\n/**\n * A collection of event handlers specific to how the user interacts with all\n * previews. The event handlers are are agnostic to how/when they are bound\n * //but not to what they are bound//, i.e. the showSettings event handler is\n * written to be bound to either an `<a>` or `<button>` element.\n *\n * @typedef {Object} ext.popups.PreviewBehavior\n * @property {String} settingsUrl\n * @property {Function} showSettings\n * @property {Function} previewDwell\n * @property {Function} previewAbandon\n * @property {Function} click handler for the entire preview\n */\n\n/**\n * Creates an instance of `ext.popups.PreviewBehavior`.\n *\n * If the user is logged out, then clicking the cog should show the settings\n * modal.\n *\n * If the user is logged in, then clicking the cog should send them to the\n * Special:Preferences page with the \"Beta features\" tab open if Page Previews\n * is enabled as a beta feature, or the \"Appearance\" tab otherwise.\n *\n * @param {mw.Map} config\n * @param {mw.User} user\n * @param {Object} actions The action creators bound to the Redux store\n * @return {ext.popups.PreviewBehavior}\n */\nfunction createPreviewBehavior( config, user, actions ) {\n\tvar isBetaFeature = config.get( 'wgPopupsBetaFeature' ),\n\t\trawTitle,\n\t\tsettingsUrl,\n\t\tshowSettings = $.noop;\n\n\tif ( user.isAnon() ) {\n\t\tshowSettings = function ( event ) {\n\t\t\tevent.preventDefault();\n\n\t\t\tactions.showSettings();\n\t\t};\n\t} else {\n\t\trawTitle = 'Special:Preferences#mw-prefsection-';\n\t\trawTitle += isBetaFeature ? 'betafeatures' : 'rendering';\n\n\t\tsettingsUrl = mw.Title.newFromText( rawTitle )\n\t\t\t.getUrl();\n\t}\n\n\treturn {\n\t\tsettingsUrl: settingsUrl,\n\t\tshowSettings: showSettings,\n\t\tpreviewDwell: actions.previewDwell,\n\t\tpreviewAbandon: actions.abandon,\n\t\tpreviewShow: actions.previewShow,\n\t\tclick: actions.linkClick\n\t};\n}\n\n\n/***/ }),\n\n/***/ \"./src/reducers/eventLogging.js\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony export (immutable) */ __webpack_exports__[\"a\"] = eventLogging;\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__actionTypes__ = __webpack_require__(\"./src/actionTypes.js\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__nextState__ = __webpack_require__(\"./src/reducers/nextState.js\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__counts__ = __webpack_require__(\"./src/counts.js\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__counts___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_2__counts__);\n/**\n * @module reducers/eventLogging\n */\n\n\n\n\n\n/**\n * Initialize the data that's shared between all events.\n *\n * @param {Object} bootAction\n * @return {Object}\n */\nfunction getBaseData( bootAction ) {\n\tvar result = {\n\t\tpageTitleSource: bootAction.page.title,\n\t\tnamespaceIdSource: bootAction.page.namespaceID,\n\t\tpageIdSource: bootAction.page.id,\n\t\tisAnon: bootAction.user.isAnon,\n\t\tpopupEnabled: bootAction.isEnabled,\n\t\tpageToken: bootAction.pageToken,\n\t\tsessionToken: bootAction.sessionToken,\n\t\tpreviewCountBucket: __WEBPACK_IMPORTED_MODULE_2__counts__[\"getPreviewCountBucket\"]( bootAction.user.previewCount ),\n\t\thovercardsSuppressedByGadget: bootAction.isNavPopupsEnabled\n\t};\n\n\tif ( !bootAction.user.isAnon ) {\n\t\tresult.editCountBucket = __WEBPACK_IMPORTED_MODULE_2__counts__[\"getEditCountBucket\"]( bootAction.user.editCount );\n\t}\n\n\treturn result;\n}\n\n/**\n * Takes data specific to the action and adds the following properties:\n *\n * * `linkInteractionToken`;\n * * `pageTitleHover` and `namespaceIdHover`; and\n * * `previewType` and `perceivedWait`, if a preview has been shown.\n *\n * @param {Object} interaction\n * @param {Object} actionData Data specific to the action, e.g. see\n * {@link module:reducers/eventLogging~createClosingEvent `createClosingEvent`}\n * @return {Object}\n */\nfunction createEvent( interaction, actionData ) {\n\tactionData.linkInteractionToken = interaction.token;\n\tactionData.pageTitleHover = interaction.title;\n\tactionData.namespaceIdHover = interaction.namespaceID;\n\n\t// Has the preview been shown?\n\tif ( interaction.timeToPreviewShow !== undefined ) {\n\t\tactionData.previewType = interaction.previewType;\n\t\tactionData.perceivedWait = interaction.timeToPreviewShow;\n\t}\n\n\treturn actionData;\n}\n\n/**\n * Creates an event that, when mixed into the base data (see\n * {@link module:reducers/eventLogging~getBaseData `getBaseData`}), represents\n * the user abandoning a link or preview.\n *\n * Since the event should be logged when the user has either abandoned a link or\n * dwelled on a different link, we refer to these events as \"closing\" events as\n * the link interaction has finished and a new one will be created later.\n *\n * If the link interaction is finalized, then no closing event is created.\n *\n * @param {Object} interaction\n * @return {Object|undefined}\n */\nfunction createClosingEvent( interaction ) {\n\tvar actionData = {\n\t\ttotalInteractionTime: Math.round( interaction.finished - interaction.started )\n\t};\n\n\tif ( interaction.finalized ) {\n\t\treturn undefined;\n\t}\n\n\t// Has the preview been shown? If so, then, in the context of the\n\t// instrumentation, then the preview has been dismissed by the user\n\t// rather than the user has abandoned the link.\n\tactionData.action = interaction.timeToPreviewShow ? 'dismissed' : 'dwelledButAbandoned';\n\n\treturn createEvent( interaction, actionData );\n}\n\n/**\n * Reducer for actions that may result in an event being logged with [the\n * Popups schema][0] via EventLogging.\n *\n * The complexity of this reducer reflects the complexity of [the schema][0],\n * which is compounded by the introduction of two delays introduced by the\n * system to provide reasonable performance and a consistent UX.\n *\n * The reducer must:\n *\n * * Accumulate the state required to log events. This state is\n * referred to as \"the interaction state\" or \"the interaction\";\n * * Enforce the invariant that one event is logged per interaction;\n * * Defend against delayed actions being dispatched; and, as a direct\n * consequence\n * * Handle transitioning from one interaction to another at the same time.\n *\n * Furthermore, we distinguish between \"finalizing\" and \"closing\" the current\n * interaction state. Since only one event should be logged per link\n * interaction, we say that the interaction state is *finalized* when an event\n * has been logged and is *closed* when a new interaction should be created.\n * In practice, the interaction state is only finalized when the user clicks a\n * link or a preview.\n *\n * [0]: https://meta.wikimedia.org/wiki/Schema:Popups\n *\n * @param {Object} state\n * @param {Object} action\n * @return {Object} The state resulting from reducing the action with the\n * current state\n */\nfunction eventLogging( state, action ) {\n\tvar nextCount, newState,\n\t\tactionTypesWithTokens = [\n\t\t\t__WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].FETCH_COMPLETE,\n\t\t\t__WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].ABANDON_END,\n\t\t\t__WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].PREVIEW_SHOW\n\t\t];\n\n\tif ( state === undefined ) {\n\t\tstate = {\n\t\t\tpreviewCount: undefined,\n\t\t\tbaseData: {},\n\t\t\tinteraction: undefined,\n\t\t\tevent: undefined\n\t\t};\n\t}\n\n\t// Was the action delayed? Then it requires a token to be reduced. Enforce\n\t// this here to avoid repetion and reduce nesting below.\n\tif (\n\t\tactionTypesWithTokens.indexOf( action.type ) !== -1 &&\n\t\t( !state.interaction || action.token !== state.interaction.token )\n\t) {\n\t\treturn state;\n\t}\n\n\t// If there is no interaction ongoing, ignore all actions except for:\n\t// * Application initialization\n\t// * New link dwells (which start a new interaction)\n\t// * Clearing queued events\n\t//\n\t// For example, after ctrl+clicking a link or preview, any other actions\n\t// until the new interaction should be ignored.\n\tif (\n\t\t!state.interaction &&\n\t\taction.type !== __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].BOOT &&\n\t\taction.type !== __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].LINK_DWELL &&\n\t\taction.type !== __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].EVENT_LOGGED &&\n\t\taction.type !== __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].SETTINGS_CHANGE\n\t) {\n\t\treturn state;\n\t}\n\tswitch ( action.type ) {\n\t\tcase __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].BOOT:\n\t\t\treturn __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__nextState__[\"a\" /* default */])( state, {\n\t\t\t\tpreviewCount: action.user.previewCount,\n\t\t\t\tbaseData: getBaseData( action ),\n\t\t\t\tevent: {\n\t\t\t\t\taction: 'pageLoaded'\n\t\t\t\t}\n\t\t\t} );\n\n\t\tcase __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].EVENT_LOGGED:\n\t\t\tnewState = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__nextState__[\"a\" /* default */])( state, {\n\t\t\t\tevent: undefined\n\t\t\t} );\n\n\t\t\t// If an event was logged with an interaction token, and it is still\n\t\t\t// the current interaction, finish the interaction since logging is\n\t\t\t// the exit point of the state machine and an interaction should never\n\t\t\t// be logged twice.\n\t\t\tif (\n\t\t\t\taction.event.linkInteractionToken &&\n\t\t\t\tstate.interaction &&\n\t\t\t\t( action.event.linkInteractionToken === state.interaction.token )\n\t\t\t) {\n\t\t\t\tnewState.interaction = undefined;\n\t\t\t}\n\t\t\treturn newState;\n\n\t\tcase __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].FETCH_COMPLETE:\n\t\t\treturn __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__nextState__[\"a\" /* default */])( state, {\n\t\t\t\tinteraction: __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__nextState__[\"a\" /* default */])( state.interaction, {\n\t\t\t\t\tpreviewType: action.result.type\n\t\t\t\t} )\n\t\t\t} );\n\n\t\tcase __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].PREVIEW_SHOW:\n\t\t\tnextCount = state.previewCount + 1;\n\n\t\t\treturn __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__nextState__[\"a\" /* default */])( state, {\n\t\t\t\tpreviewCount: nextCount,\n\t\t\t\tbaseData: __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__nextState__[\"a\" /* default */])( state.baseData, {\n\t\t\t\t\tpreviewCountBucket: __WEBPACK_IMPORTED_MODULE_2__counts__[\"getPreviewCountBucket\"]( nextCount )\n\t\t\t\t} ),\n\t\t\t\tinteraction: __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__nextState__[\"a\" /* default */])( state.interaction, {\n\t\t\t\t\ttimeToPreviewShow: Math.round( action.timestamp - state.interaction.started )\n\t\t\t\t} )\n\t\t\t} );\n\n\t\tcase __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].LINK_DWELL:\n\n\t\t\t// Not a new interaction?\n\t\t\tif ( state.interaction && action.el === state.interaction.link ) {\n\t\t\t\treturn __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__nextState__[\"a\" /* default */])( state, {\n\t\t\t\t\tinteraction: __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__nextState__[\"a\" /* default */])( state.interaction, {\n\t\t\t\t\t\tisUserDwelling: true\n\t\t\t\t\t} )\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\treturn __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__nextState__[\"a\" /* default */])( state, {\n\n\t\t\t\t// TODO: Extract this object into a module that can be shared between\n\t\t\t\t// this and the preview reducer.\n\t\t\t\tinteraction: {\n\t\t\t\t\tlink: action.el,\n\t\t\t\t\ttitle: action.title,\n\t\t\t\t\tnamespaceID: action.namespaceID,\n\t\t\t\t\ttoken: action.token,\n\t\t\t\t\tstarted: action.timestamp,\n\n\t\t\t\t\tisUserDwelling: true\n\t\t\t\t},\n\n\t\t\t\t// Was the user interacting with another link? If so, then log the\n\t\t\t\t// abandoned event.\n\t\t\t\tevent: state.interaction ? createClosingEvent( state.interaction ) : undefined\n\t\t\t} );\n\n\t\tcase __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].PREVIEW_DWELL:\n\t\t\treturn __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__nextState__[\"a\" /* default */])( state, {\n\t\t\t\tinteraction: __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__nextState__[\"a\" /* default */])( state.interaction, {\n\t\t\t\t\tisUserDwelling: true\n\t\t\t\t} )\n\t\t\t} );\n\n\t\tcase __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].LINK_CLICK:\n\t\t\treturn __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__nextState__[\"a\" /* default */])( state, {\n\t\t\t\tinteraction: __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__nextState__[\"a\" /* default */])( state.interaction, {\n\t\t\t\t\tfinalized: true\n\t\t\t\t} ),\n\t\t\t\tevent: createEvent( state.interaction, {\n\t\t\t\t\taction: 'opened',\n\t\t\t\t\ttotalInteractionTime: Math.round( action.timestamp - state.interaction.started )\n\t\t\t\t} )\n\t\t\t} );\n\n\t\tcase __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].ABANDON_START:\n\t\t\treturn __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__nextState__[\"a\" /* default */])( state, {\n\t\t\t\tinteraction: __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__nextState__[\"a\" /* default */])( state.interaction, {\n\t\t\t\t\tfinished: action.timestamp,\n\n\t\t\t\t\tisUserDwelling: false\n\t\t\t\t} )\n\t\t\t} );\n\n\t\tcase __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].ABANDON_END:\n\t\t\tif ( !state.interaction.isUserDwelling ) {\n\t\t\t\treturn __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__nextState__[\"a\" /* default */])( state, {\n\t\t\t\t\tinteraction: undefined,\n\t\t\t\t\tevent: createClosingEvent( state.interaction )\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\treturn state;\n\n\t\tcase __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].SETTINGS_SHOW:\n\t\t\treturn __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__nextState__[\"a\" /* default */])( state, {\n\t\t\t\tevent: createEvent( state.interaction, {\n\t\t\t\t\taction: 'tapped settings cog'\n\t\t\t\t} )\n\t\t\t} );\n\n\t\tcase __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].SETTINGS_CHANGE:\n\t\t\tif ( action.wasEnabled && !action.enabled ) {\n\t\t\t\treturn __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__nextState__[\"a\" /* default */])( state, {\n\t\t\t\t\tevent: {\n\t\t\t\t\t\taction: 'disabled',\n\t\t\t\t\t\tpopupEnabled: false\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t} else {\n\t\t\t\treturn state;\n\t\t\t}\n\t\tdefault:\n\t\t\treturn state;\n\t}\n}\n\n\n/***/ }),\n\n/***/ \"./src/reducers/index.js\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__eventLogging__ = __webpack_require__(\"./src/reducers/eventLogging.js\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__preview__ = __webpack_require__(\"./src/reducers/preview.js\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__settings__ = __webpack_require__(\"./src/reducers/settings.js\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__statsv__ = __webpack_require__(\"./src/reducers/statsv.js\");\n\n\n\n\n\n/* harmony default export */ __webpack_exports__[\"a\"] = ({\n\teventLogging: __WEBPACK_IMPORTED_MODULE_0__eventLogging__[\"a\" /* default */],\n\tpreview: __WEBPACK_IMPORTED_MODULE_1__preview__[\"a\" /* default */],\n\tsettings: __WEBPACK_IMPORTED_MODULE_2__settings__[\"a\" /* default */],\n\tstatsv: __WEBPACK_IMPORTED_MODULE_3__statsv__[\"a\" /* default */]\n});\n\n\n/***/ }),\n\n/***/ \"./src/reducers/nextState.js\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony export (immutable) */ __webpack_exports__[\"a\"] = nextState;\n/**\n * Creates the next state tree from the current state tree and some updates.\n *\n * N.B. OO.copy doesn't copy Element instances, whereas $.extend does.\n * However, OO.copy does copy properties whose values are undefined or null,\n * whereas $.extend doesn't. Since the state tree contains an Element instance\n * - the preview.activeLink property - and we want to copy undefined/null into\n * the state we need to manually iterate over updates and check with\n * hasOwnProperty to copy over to the new state.\n *\n * In [change listeners](/doc/change_listeners.md), for example, we talk about\n * the previous state and the current state (the `prevState` and `state`\n * parameters, respectively). Since\n * [reducers](http://redux.js.org/docs/basics/Reducers.html) take the current\n * state and an action and make updates, \"next state\" seems appropriate.\n *\n * @param {Object} state\n * @param {Object} updates\n * @return {Object}\n */\nfunction nextState( state, updates ) {\n\tvar result = {},\n\t\tkey;\n\n\tfor ( key in state ) {\n\t\tif ( state.hasOwnProperty( key ) && !updates.hasOwnProperty( key ) ) {\n\t\t\tresult[ key ] = state[ key ];\n\t\t}\n\t}\n\n\tfor ( key in updates ) {\n\t\tif ( updates.hasOwnProperty( key ) ) {\n\t\t\tresult[ key ] = updates[ key ];\n\t\t}\n\t}\n\n\treturn result;\n}\n\n\n/***/ }),\n\n/***/ \"./src/reducers/preview.js\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony export (immutable) */ __webpack_exports__[\"a\"] = preview;\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__actionTypes__ = __webpack_require__(\"./src/actionTypes.js\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__nextState__ = __webpack_require__(\"./src/reducers/nextState.js\");\n\n\n\n/**\n * Reducer for actions that modify the state of the preview model\n *\n * @param {Object} state before action\n * @param {Object} action Redux action that modified state.\n * Must have `type` property.\n * @return {Object} state after action\n */\nfunction preview( state, action ) {\n\tif ( state === undefined ) {\n\t\tstate = {\n\t\t\tenabled: undefined,\n\t\t\tactiveLink: undefined,\n\t\t\tactiveEvent: undefined,\n\t\t\tactiveToken: '',\n\t\t\tshouldShow: false,\n\t\t\tisUserDwelling: false\n\t\t};\n\t}\n\n\tswitch ( action.type ) {\n\t\tcase __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].BOOT:\n\t\t\treturn __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__nextState__[\"a\" /* default */])( state, {\n\t\t\t\tenabled: action.isEnabled\n\t\t\t} );\n\t\tcase __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].SETTINGS_CHANGE:\n\t\t\treturn __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__nextState__[\"a\" /* default */])( state, {\n\t\t\t\tenabled: action.enabled\n\t\t\t} );\n\t\tcase __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].LINK_DWELL:\n\t\t\t// New interaction\n\t\t\tif ( action.el !== state.activeLink ) {\n\t\t\t\treturn __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__nextState__[\"a\" /* default */])( state, {\n\t\t\t\t\tactiveLink: action.el,\n\t\t\t\t\tactiveEvent: action.event,\n\t\t\t\t\tactiveToken: action.token,\n\n\t\t\t\t\t// When the user dwells on a link with their keyboard, a preview is\n\t\t\t\t\t// renderered, and then dwells on another link, the ABANDON_END\n\t\t\t\t\t// action will be ignored.\n\t\t\t\t\t//\n\t\t\t\t\t// Ensure that all the preview is hidden.\n\t\t\t\t\tshouldShow: false,\n\n\t\t\t\t\tisUserDwelling: true\n\t\t\t\t} );\n\t\t\t} else {\n\t\t\t\t// Dwelling back into the same link\n\t\t\t\treturn __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__nextState__[\"a\" /* default */])( state, {\n\t\t\t\t\tisUserDwelling: true\n\t\t\t\t} );\n\t\t\t}\n\n\t\tcase __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].ABANDON_END:\n\t\t\tif ( action.token === state.activeToken && !state.isUserDwelling ) {\n\t\t\t\treturn __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__nextState__[\"a\" /* default */])( state, {\n\t\t\t\t\tactiveLink: undefined,\n\t\t\t\t\tactiveToken: undefined,\n\t\t\t\t\tactiveEvent: undefined,\n\t\t\t\t\tfetchResponse: undefined,\n\t\t\t\t\tshouldShow: false\n\t\t\t\t} );\n\t\t\t}\n\t\t\treturn state;\n\n\t\tcase __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].PREVIEW_DWELL:\n\t\t\treturn __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__nextState__[\"a\" /* default */])( state, {\n\t\t\t\tisUserDwelling: true\n\t\t\t} );\n\n\t\tcase __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].ABANDON_START:\n\t\t\treturn __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__nextState__[\"a\" /* default */])( state, {\n\t\t\t\tisUserDwelling: false\n\t\t\t} );\n\n\t\tcase __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].FETCH_START:\n\t\t\treturn __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__nextState__[\"a\" /* default */])( state, {\n\t\t\t\tfetchResponse: undefined\n\t\t\t} );\n\t\tcase __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].FETCH_COMPLETE:\n\t\t\tif ( action.token === state.activeToken ) {\n\t\t\t\treturn __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__nextState__[\"a\" /* default */])( state, {\n\t\t\t\t\tfetchResponse: action.result,\n\t\t\t\t\tshouldShow: state.isUserDwelling\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\t/* falls through */\n\t\tdefault:\n\t\t\treturn state;\n\t}\n}\n\n\n/***/ }),\n\n/***/ \"./src/reducers/settings.js\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony export (immutable) */ __webpack_exports__[\"a\"] = settings;\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__actionTypes__ = __webpack_require__(\"./src/actionTypes.js\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__nextState__ = __webpack_require__(\"./src/reducers/nextState.js\");\n\n\n\n/**\n * Reducer for actions that modify the state of the settings\n *\n * @param {Object} state\n * @param {Object} action\n * @return {Object} state after action\n */\nfunction settings( state, action ) {\n\tif ( state === undefined ) {\n\t\tstate = {\n\t\t\tshouldShow: false,\n\t\t\tshowHelp: false,\n\t\t\tshouldShowFooterLink: false\n\t\t};\n\t}\n\n\tswitch ( action.type ) {\n\t\tcase __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].SETTINGS_SHOW:\n\t\t\treturn __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__nextState__[\"a\" /* default */])( state, {\n\t\t\t\tshouldShow: true,\n\t\t\t\tshowHelp: false\n\t\t\t} );\n\t\tcase __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].SETTINGS_HIDE:\n\t\t\treturn __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__nextState__[\"a\" /* default */])( state, {\n\t\t\t\tshouldShow: false,\n\t\t\t\tshowHelp: false\n\t\t\t} );\n\t\tcase __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].SETTINGS_CHANGE:\n\t\t\treturn action.wasEnabled === action.enabled ?\n\t\t\t\t// If the setting is the same, just hide the dialogs\n\t\t\t\t__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__nextState__[\"a\" /* default */])( state, {\n\t\t\t\t\tshouldShow: false\n\t\t\t\t} ) :\n\t\t\t\t// If the settings have changed...\n\t\t\t\t__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__nextState__[\"a\" /* default */])( state, {\n\t\t\t\t\t// If we enabled, we just hide directly, no help\n\t\t\t\t\t// If we disabled, keep it showing and let the ui show the help.\n\t\t\t\t\tshouldShow: !action.enabled,\n\t\t\t\t\tshowHelp: !action.enabled,\n\n\t\t\t\t\t// Since the footer link is only ever shown to anonymous users (see\n\t\t\t\t\t// the BOOT case below), state.userIsAnon is always truthy here.\n\t\t\t\t\tshouldShowFooterLink: !action.enabled\n\t\t\t\t} );\n\n\t\tcase __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].BOOT:\n\t\t\treturn __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__nextState__[\"a\" /* default */])( state, {\n\t\t\t\tshouldShowFooterLink: action.user.isAnon && !action.isEnabled\n\t\t\t} );\n\t\tdefault:\n\t\t\treturn state;\n\t}\n}\n\n\n/***/ }),\n\n/***/ \"./src/reducers/statsv.js\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony export (immutable) */ __webpack_exports__[\"a\"] = statsv;\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__actionTypes__ = __webpack_require__(\"./src/actionTypes.js\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__nextState__ = __webpack_require__(\"./src/reducers/nextState.js\");\n\n\n\n/**\n * Reducer for actions that may result in an event being logged via statsv.\n *\n * @param {Object} state\n * @param {Object} action\n * @return {Object} state after action\n */\nfunction statsv( state, action ) {\n\tstate = state || {};\n\n\tswitch ( action.type ) {\n\t\tcase __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].FETCH_START:\n\t\t\treturn __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__nextState__[\"a\" /* default */])( state, {\n\t\t\t\tfetchStartedAt: action.timestamp\n\t\t\t} );\n\n\t\tcase __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].FETCH_END:\n\t\t\treturn __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__nextState__[\"a\" /* default */])( state, {\n\t\t\t\taction: 'timing.PagePreviewsApiResponse',\n\t\t\t\tdata: action.timestamp - state.fetchStartedAt\n\t\t\t} );\n\n\t\tcase __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].FETCH_FAILED:\n\t\t\treturn __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__nextState__[\"a\" /* default */])( state, {\n\t\t\t\taction: 'counter.PagePreviewsApiFailure',\n\t\t\t\tdata: 1\n\t\t\t} );\n\n\t\tcase __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].LINK_DWELL:\n\t\t\treturn __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__nextState__[\"a\" /* default */])( state, {\n\t\t\t\tlinkDwellStartedAt: action.timestamp\n\t\t\t} );\n\n\t\tcase __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].PREVIEW_SHOW:\n\t\t\treturn __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__nextState__[\"a\" /* default */])( state, {\n\t\t\t\taction: 'timing.PagePreviewsPreviewShow',\n\t\t\t\tdata: action.timestamp - state.linkDwellStartedAt\n\t\t\t} );\n\n\t\tcase __WEBPACK_IMPORTED_MODULE_0__actionTypes__[\"a\" /* default */].STATSV_LOGGED:\n\t\t\treturn __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__nextState__[\"a\" /* default */])( state, {\n\t\t\t\taction: null,\n\t\t\t\tdata: null\n\t\t\t} );\n\n\t\tdefault:\n\t\t\treturn state;\n\t}\n}\n\n\n/***/ }),\n\n/***/ \"./src/title.js\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* unused harmony export getTitle */\n/* unused harmony export isValid */\n/* harmony export (immutable) */ __webpack_exports__[\"a\"] = fromElement;\n/**\n * @module title\n */\n\nvar mw = window.mediaWiki;\n\n/**\n * Gets the title of a local page from an href given some configuration.\n *\n * @param {String} href\n * @param {mw.Map} config\n * @return {String|undefined}\n */\nfunction getTitle( href, config ) {\n\tvar linkHref,\n\t\tmatches,\n\t\tqueryLength,\n\t\ttitleRegex = new RegExp( mw.RegExp.escape( config.get( 'wgArticlePath' ) )\n\t\t\t.replace( '\\\\$1', '(.+)' ) );\n\n\t// Skip every URI that mw.Uri cannot parse\n\ttry {\n\t\tlinkHref = new mw.Uri( href );\n\t} catch ( e ) {\n\t\treturn undefined;\n\t}\n\n\t// External links\n\tif ( linkHref.host !== location.hostname ) {\n\t\treturn undefined;\n\t}\n\n\tqueryLength = Object.keys( linkHref.query ).length;\n\n\t// No query params (pretty URL)\n\tif ( !queryLength ) {\n\t\tmatches = titleRegex.exec( linkHref.path );\n\t\treturn matches ? decodeURIComponent( matches[ 1 ] ) : undefined;\n\t} else if ( queryLength === 1 && linkHref.query.hasOwnProperty( 'title' ) ) {\n\t\t// URL is not pretty, but only has a `title` parameter\n\t\treturn linkHref.query.title;\n\t}\n\n\treturn undefined;\n}\n\n/**\n * Given a page title it will return the mediawiki.Title if it is an eligible\n * link for showing page previews, null otherwise\n *\n * @param {String} title page title to check if it should show preview\n * @param {Number[]} contentNamespaces contentNamespaces as specified in\n * wgContentNamespaces\n * @returns {mw.Title|null}\n */\nfunction isValid( title, contentNamespaces ) {\n\tvar mwTitle;\n\n\tif ( !title ) {\n\t\treturn null;\n\t}\n\n\t// Is title in a content namespace?\n\tmwTitle = mw.Title.newFromText( title );\n\tif ( mwTitle && ( $.inArray( mwTitle.namespace, contentNamespaces ) >= 0 ) ) {\n\t\treturn mwTitle;\n\t}\n\n\treturn null;\n}\n\n/**\n * Return a mw.Title from a HTMLElement if valid for hovercards. Convenience\n * method\n *\n * @param {Element} el\n * @param {mw.Map} config\n * @return {mw.Title|null}\n */\nfunction fromElement( el, config ) {\n\treturn isValid( getTitle( el.href, config ), config.get( 'wgContentNamespaces' ) );\n}\n\n\n/***/ }),\n\n/***/ \"./src/ui/renderer.js\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* unused harmony export createPokeyMasks */\n/* harmony export (immutable) */ __webpack_exports__[\"a\"] = init;\n/* harmony export (immutable) */ __webpack_exports__[\"b\"] = render;\n/* unused harmony export createPreview */\n/* unused harmony export createEmptyPreview */\n/* unused harmony export show */\n/* unused harmony export bindBehavior */\n/* unused harmony export hide */\n/* unused harmony export createThumbnail */\n/* unused harmony export createThumbnailElement */\n/* unused harmony export createLayout */\n/* unused harmony export getClasses */\n/* unused harmony export layoutPreview */\n/* unused harmony export getClosestYPosition */\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__wait__ = __webpack_require__(\"./src/wait.js\");\n/**\n * @module renderer\n */\n\n\n\nvar mw = window.mediaWiki,\n\t$ = jQuery,\n\tSIZES = {\n\t\tportraitImage: {\n\t\t\th: 250, // Exact height\n\t\t\tw: 203 // Max width\n\t\t},\n\t\tlandscapeImage: {\n\t\t\th: 200, // Max height\n\t\t\tw: 320 // Exact Width\n\t\t},\n\t\tlandscapePopupWidth: 450,\n\t\tportraitPopupWidth: 320,\n\t\tpokeySize: 8 // Height of the pokey.\n\t},\n\t$window = $( window );\n\n/**\n * Extracted from `mw.popups.createSVGMasks`.\n * @private\n * @param {Object} container DOM object to which pokey masks are appended\n */\nfunction createPokeyMasks( container ) {\n\t$( '<div>' )\n\t\t.attr( 'id', 'mwe-popups-svg' )\n\t\t.html(\n\t\t\t'<svg width=\"0\" height=\"0\">' +\n\t\t\t\t'<defs>' +\n\t\t\t\t\t'<clippath id=\"mwe-popups-mask\">' +\n\t\t\t\t\t\t'<polygon points=\"0 8, 10 8, 18 0, 26 8, 1000 8, 1000 1000, 0 1000\"/>' +\n\t\t\t\t\t'</clippath>' +\n\t\t\t\t\t'<clippath id=\"mwe-popups-mask-flip\">' +\n\t\t\t\t\t\t'<polygon points=\"0 8, 274 8, 282 0, 290 8, 1000 8, 1000 1000, 0 1000\"/>' +\n\t\t\t\t\t'</clippath>' +\n\t\t\t\t\t'<clippath id=\"mwe-popups-landscape-mask\">' +\n\t\t\t\t\t\t'<polygon points=\"0 8, 174 8, 182 0, 190 8, 1000 8, 1000 1000, 0 1000\"/>' +\n\t\t\t\t\t'</clippath>' +\n\t\t\t\t\t'<clippath id=\"mwe-popups-landscape-mask-flip\">' +\n\t\t\t\t\t\t'<polygon points=\"0 0, 1000 0, 1000 242, 190 242, 182 250, 174 242, 0 242\"/>' +\n\t\t\t\t\t'</clippath>' +\n\t\t\t\t'</defs>' +\n\t\t\t'</svg>'\n\t\t)\n\t\t.appendTo( container );\n}\n\n/**\n * Initializes the renderer.\n */\nfunction init() {\n\tcreatePokeyMasks( document.body );\n}\n\n/**\n * The model of how a view is rendered, which is constructed from a response\n * from the gateway.\n *\n * TODO: Rename `isTall` to `isPortrait`.\n *\n * @typedef {Object} ext.popups.Preview\n * @property {jQuery} el\n * @property {Boolean} hasThumbnail\n * @property {Object} thumbnail\n * @property {Boolean} isTall Sugar around\n * `preview.hasThumbnail && thumbnail.isTall`\n */\n\n/**\n * Renders a preview given data from the {@link gateway Gateway}.\n * The preview is rendered and added to the DOM but will remain hidden until\n * the `show` method is called.\n *\n * Previews are rendered at:\n *\n * # The position of the mouse when the user dwells on the link with their\n * mouse.\n * # The centermost point of the link when the user dwells on the link with\n * their keboard or other assistive device.\n *\n * Since the content of the preview doesn't change but its position might, we\n * distinguish between \"rendering\" - generating HTML from a MediaWiki API\n * response - and \"showing/hiding\" - positioning the layout and changing its\n * orientation, if necessary.\n *\n * @param {ext.popups.PreviewModel} model\n * @return {ext.popups.Preview}\n */\nfunction render( model ) {\n\tvar preview = model.extract === undefined ? createEmptyPreview( model ) : createPreview( model );\n\n\treturn {\n\n\t\t/**\n\t\t * Shows the preview given an event representing the user's interaction\n\t\t * with the active link, e.g. an instance of\n\t\t * [MouseEvent](https://developer.mozilla.org/en/docs/Web/API/MouseEvent).\n\t\t *\n\t\t * See `show` for more detail.\n\t\t *\n\t\t * @param {Event} event\n\t\t * @param {Object} boundActions The\n\t\t * [bound action creators](http://redux.js.org/docs/api/bindActionCreators.html)\n\t\t * that were (likely) created in [boot.js](./boot.js).\n\t\t * @param {String} token The unique token representing the link interaction\n\t\t * that resulted in showing the preview\n\t\t * @return {jQuery.Promise}\n\t\t */\n\t\tshow: function ( event, boundActions, token ) {\n\t\t\treturn show(\n\t\t\t\tpreview, event, $( event.target ), boundActions, token,\n\t\t\t\tdocument.body\n\t\t\t);\n\t\t},\n\n\t\t/**\n\t\t * Hides the preview.\n\t\t *\n\t\t * See `hide` for more detail.\n\t\t *\n\t\t * @return {jQuery.Promise}\n\t\t */\n\t\thide: function () {\n\t\t\treturn hide( preview );\n\t\t}\n\t};\n}\n\n/**\n * Creates an instance of the DTO backing a preview.\n *\n * @param {ext.popups.PreviewModel} model\n * @return {ext.popups.Preview}\n */\nfunction createPreview( model ) {\n\tvar templateData,\n\t\tthumbnail = createThumbnail( model.thumbnail ),\n\t\thasThumbnail = thumbnail !== null,\n\t\textract = model.extract,\n\t\t$el;\n\n\ttemplateData = $.extend( {}, model, {\n\t\thasThumbnail: hasThumbnail\n\t} );\n\n\t$el = mw.template.get( 'ext.popups', 'preview.mustache' )\n\t\t.render( templateData );\n\n\tif ( hasThumbnail ) {\n\t\t$el.find( '.mwe-popups-discreet' ).append( thumbnail.el );\n\t}\n\tif ( extract ) {\n\t\t$el.find( '.mwe-popups-extract' ).append( extract );\n\t}\n\n\treturn {\n\t\tel: $el,\n\t\thasThumbnail: hasThumbnail,\n\t\tthumbnail: thumbnail,\n\t\tisTall: hasThumbnail && thumbnail.isTall\n\t};\n}\n\n/**\n * Creates an instance of the DTO backing a preview. In this case the DTO\n * represents a generic preview, which covers the following scenarios:\n *\n * * The page doesn't exist, i.e. the user hovered over a redlink or a\n * redirect to a page that doesn't exist.\n * * The page doesn't have a viable extract.\n *\n * @param {ext.popups.PreviewModel} model\n * @return {ext.popups.Preview}\n */\nfunction createEmptyPreview( model ) {\n\tvar templateData,\n\t\t$el;\n\n\ttemplateData = $.extend( {}, model, {\n\t\textractMsg: mw.msg( 'popups-preview-no-preview' ),\n\t\treadMsg: mw.msg( 'popups-preview-footer-read' )\n\t} );\n\n\t$el = mw.template.get( 'ext.popups', 'preview-empty.mustache' )\n\t\t.render( templateData );\n\n\treturn {\n\t\tel: $el,\n\t\thasThumbnail: false,\n\t\tisTall: false\n\t};\n}\n\n/**\n * Shows the preview.\n *\n * Extracted from `mw.popups.render.openPopup`.\n *\n * TODO: From the perspective of the client, there's no need to distinguish\n * between renderering and showing a preview. Merge #render and Preview#show.\n *\n * @param {ext.popups.Preview} preview\n * @param {Event} event\n * @param {jQuery} $link event target\n * @param {ext.popups.PreviewBehavior} behavior\n * @param {String} token\n * @param {Object} container DOM object to which pokey masks are appended\n * @return {jQuery.Promise} A promise that resolves when the promise has faded\n * in\n */\nfunction show( preview, event, $link, behavior, token, container ) {\n\tvar layout = createLayout(\n\t\tpreview.isTall,\n\t\t{\n\t\t\tpageX: event.pageX,\n\t\t\tpageY: event.pageY,\n\t\t\tclientY: event.clientY\n\t\t},\n\t\t{\n\t\t\tclientRects: $link.get( 0 ).getClientRects(),\n\t\t\toffset: $link.offset(),\n\t\t\twidth: $link.width(),\n\t\t\theight: $link.height()\n\t\t},\n\t\t{\n\t\t\tscrollTop: $window.scrollTop(),\n\t\t\twidth: $window.width(),\n\t\t\theight: $window.height()\n\t\t},\n\t\tSIZES.pokeySize\n\t);\n\n\tpreview.el.appendTo( container );\n\n\tlayoutPreview(\n\t\tpreview, layout, getClasses( preview, layout ),\n\t\tSIZES.landscapeImage.h, SIZES.pokeySize\n\t);\n\n\tpreview.el.show();\n\n\treturn __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__wait__[\"a\" /* default */])( 200 )\n\t\t.then( function () {\n\t\t\tbindBehavior( preview, behavior );\n\t\t} )\n\t\t.then( function () {\n\t\t\tbehavior.previewShow( token );\n\t\t} );\n}\n\n/**\n * Binds the behavior to the interactive elements of the preview.\n *\n * @param {ext.popups.Preview} preview\n * @param {ext.popups.PreviewBehavior} behavior\n */\nfunction bindBehavior( preview, behavior ) {\n\tpreview.el.hover( behavior.previewDwell, behavior.previewAbandon );\n\n\tpreview.el.click( behavior.click );\n\n\tpreview.el.find( '.mwe-popups-settings-icon' )\n\t\t.attr( 'href', behavior.settingsUrl )\n\t\t.click( function ( event ) {\n\t\t\tevent.stopPropagation();\n\n\t\t\tbehavior.showSettings( event );\n\t\t} );\n}\n\n/**\n * Extracted from `mw.popups.render.closePopup`.\n *\n * @param {ext.popups.Preview} preview\n * @return {jQuery.Promise} A promise that resolves when the preview has faded\n * out\n */\nfunction hide( preview ) {\n\tvar fadeInClass,\n\t\tfadeOutClass;\n\n\t// FIXME: This method clearly needs access to the layout of the preview.\n\tfadeInClass = ( preview.el.hasClass( 'mwe-popups-fade-in-up' ) ) ?\n\t\t'mwe-popups-fade-in-up' :\n\t\t'mwe-popups-fade-in-down';\n\n\tfadeOutClass = ( fadeInClass === 'mwe-popups-fade-in-up' ) ?\n\t\t'mwe-popups-fade-out-down' :\n\t\t'mwe-popups-fade-out-up';\n\n\tpreview.el\n\t\t.removeClass( fadeInClass )\n\t\t.addClass( fadeOutClass );\n\n\treturn __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__wait__[\"a\" /* default */])( 150 ).then( function () {\n\t\tpreview.el.remove();\n\t} );\n}\n\n/**\n * @typedef {Object} ext.popups.Thumbnail\n * @property {Element} el\n * @property {Boolean} isTall Whether or not the thumbnail is portrait\n */\n\n/**\n * Creates a thumbnail from the representation of a thumbnail returned by the\n * PageImages MediaWiki API query module.\n *\n * If there's no thumbnail, the thumbnail is too small, or the thumbnail's URL\n * contains characters that could be used to perform an\n * [XSS attack via CSS](https://www.owasp.org/index.php/Testing_for_CSS_Injection_(OTG-CLIENT-005)),\n * then `null` is returned.\n *\n * Extracted from `mw.popups.renderer.article.createThumbnail`.\n *\n * @param {Object} rawThumbnail\n * @return {ext.popups.Thumbnail|null}\n */\nfunction createThumbnail( rawThumbnail ) {\n\tvar tall, thumbWidth, thumbHeight,\n\t\tx, y, width, height, clipPath,\n\t\tdevicePixelRatio = $.bracketedDevicePixelRatio();\n\n\tif ( !rawThumbnail ) {\n\t\treturn null;\n\t}\n\n\ttall = rawThumbnail.width < rawThumbnail.height;\n\tthumbWidth = rawThumbnail.width / devicePixelRatio;\n\tthumbHeight = rawThumbnail.height / devicePixelRatio;\n\n\tif (\n\t\t// Image too small for landscape display\n\t\t( !tall && thumbWidth < SIZES.landscapeImage.w ) ||\n\t\t// Image too small for portrait display\n\t\t( tall && thumbHeight < SIZES.portraitImage.h ) ||\n\t\t// These characters in URL that could inject CSS and thus JS\n\t\t(\n\t\t\trawThumbnail.source.indexOf( '\\\\' ) > -1 ||\n\t\t\trawThumbnail.source.indexOf( '\\'' ) > -1 ||\n\t\t\trawThumbnail.source.indexOf( '\\\"' ) > -1\n\t\t)\n\t) {\n\t\treturn null;\n\t}\n\n\tif ( tall ) {\n\t\tx = ( thumbWidth > SIZES.portraitImage.w ) ?\n\t\t\t( ( thumbWidth - SIZES.portraitImage.w ) / -2 ) :\n\t\t\t( SIZES.portraitImage.w - thumbWidth );\n\t\ty = ( thumbHeight > SIZES.portraitImage.h ) ?\n\t\t\t( ( thumbHeight - SIZES.portraitImage.h ) / -2 ) : 0;\n\t\twidth = SIZES.portraitImage.w;\n\t\theight = SIZES.portraitImage.h;\n\t} else {\n\t\tx = 0;\n\t\ty = ( thumbHeight > SIZES.landscapeImage.h ) ?\n\t\t\t( ( thumbHeight - SIZES.landscapeImage.h ) / -2 ) : 0;\n\t\twidth = SIZES.landscapeImage.w + 3;\n\t\theight = ( thumbHeight > SIZES.landscapeImage.h ) ?\n\t\t\tSIZES.landscapeImage.h : thumbHeight;\n\t\tclipPath = 'mwe-popups-mask';\n\t}\n\n\treturn {\n\t\tel: createThumbnailElement(\n\t\t\ttall ? 'mwe-popups-is-tall' : 'mwe-popups-is-not-tall',\n\t\t\trawThumbnail.source,\n\t\t\tx,\n\t\t\ty,\n\t\t\tthumbWidth,\n\t\t\tthumbHeight,\n\t\t\twidth,\n\t\t\theight,\n\t\t\tclipPath\n\t\t),\n\t\tisTall: tall,\n\t\twidth: thumbWidth,\n\t\theight: thumbHeight\n\t};\n}\n\n/**\n * Creates the SVG image element that represents the thumbnail.\n *\n * This function is distinct from `createThumbnail` as it abstracts away some\n * browser issues that are uncovered when manipulating elements across\n * namespaces.\n *\n * @param {String} className\n * @param {String} url\n * @param {Number} x\n * @param {Number} y\n * @param {Number} thumbnailWidth\n * @param {Number} thumbnailHeight\n * @param {Number} width\n * @param {Number} height\n * @param {String} clipPath\n * @return {jQuery}\n */\nfunction createThumbnailElement( className, url, x, y, thumbnailWidth, thumbnailHeight, width, height, clipPath ) {\n\tvar $thumbnailSVGImage, $thumbnail,\n\t\tnsSvg = 'http://www.w3.org/2000/svg',\n\t\tnsXlink = 'http://www.w3.org/1999/xlink';\n\n\t$thumbnailSVGImage = $( document.createElementNS( nsSvg, 'image' ) );\n\t$thumbnailSVGImage[ 0 ].setAttributeNS( nsXlink, 'href', url );\n\t$thumbnailSVGImage\n\t\t.addClass( className )\n\t\t.attr( {\n\t\t\tx: x,\n\t\t\ty: y,\n\t\t\twidth: thumbnailWidth,\n\t\t\theight: thumbnailHeight,\n\t\t\t'clip-path': 'url(#' + clipPath + ')'\n\t\t} );\n\n\t$thumbnail = $( document.createElementNS( nsSvg, 'svg' ) )\n\t\t.attr( {\n\t\t\txmlns: nsSvg,\n\t\t\twidth: width,\n\t\t\theight: height\n\t\t} )\n\t\t.append( $thumbnailSVGImage );\n\n\treturn $thumbnail;\n}\n\n/**\n * Represents the layout of a preview, which consists of a position (`offset`)\n * and whether or not the preview should be flipped horizontally or\n * vertically (`flippedX` and `flippedY` respectively).\n *\n * @typedef {Object} ext.popups.PreviewLayout\n * @property {Object} offset\n * @property {number} offset.top\n * @property {number} offset.left\n * @property {Boolean} flippedX\n * @property {Boolean} flippedY\n */\n\n/**\n * @param {isPreviewTall} isPreviewTall\n * @param {Object} eventData Data related to the event that triggered showing a popup\n * @param {number} eventData.pageX\n * @param {number} eventData.pageY\n * @param {number} eventData.clientY\n * @param {Object} linkData Data related to the link that’s used for showing a popup\n * @param {ClientRectList} linkData.clientRects list of rectangles defined by four edges\n * @param {Object} linkData.offset\n * @param {number} linkData.width\n * @param {number} linkData.height\n * @param {Object} windowData Data related to the window\n * @param {number} windowData.scrollTop\n * @param {number} windowData.width\n * @param {number} windowData.height\n * @param {number} pokeySize Space reserved for the pokey\n * @return {ext.popups.PreviewLayout}\n */\nfunction createLayout( isPreviewTall, eventData, linkData, windowData, pokeySize ) {\n\tvar flippedX = false,\n\t\tflippedY = false,\n\t\toffsetTop = ( eventData.pageY ) ? // If it was a mouse event\n\t\t\t// Position according to mouse\n\t\t\t// Since client rectangles are relative to the viewport,\n\t\t\t// take scroll position into account.\n\t\t\tgetClosestYPosition(\n\t\t\t\teventData.pageY - windowData.scrollTop,\n\t\t\t\tlinkData.clientRects,\n\t\t\t\tfalse\n\t\t\t) + windowData.scrollTop + pokeySize :\n\t\t\t// Position according to link position or size\n\t\t\tlinkData.offset.top + linkData.height + pokeySize,\n\t\tclientTop = ( eventData.clientY ) ?\n\t\t\teventData.clientY :\n\t\t\toffsetTop,\n\t\toffsetLeft = ( eventData.pageX ) ?\n\t\t\teventData.pageX :\n\t\t\tlinkData.offset.left;\n\n\t// X Flip\n\tif ( offsetLeft > ( windowData.width / 2 ) ) {\n\t\toffsetLeft += ( !eventData.pageX ) ? linkData.width : 0;\n\t\toffsetLeft -= !isPreviewTall ?\n\t\t\tSIZES.portraitPopupWidth :\n\t\t\tSIZES.landscapePopupWidth;\n\t\tflippedX = true;\n\t}\n\n\tif ( eventData.pageX ) {\n\t\toffsetLeft += ( flippedX ) ? 20 : -20;\n\t}\n\n\t// Y Flip\n\tif ( clientTop > ( windowData.height / 2 ) ) {\n\t\tflippedY = true;\n\n\t\t// Mirror the positioning of the preview when there's no \"Y flip\": rest\n\t\t// the pokey on the edge of the link's bounding rectangle. In this case\n\t\t// the edge is the top-most.\n\t\toffsetTop = linkData.offset.top;\n\n\t\t// Change the Y position to the top of the link\n\t\tif ( eventData.pageY ) {\n\t\t\t// Since client rectangles are relative to the viewport,\n\t\t\t// take scroll position into account.\n\t\t\toffsetTop = getClosestYPosition(\n\t\t\t\teventData.pageY - windowData.scrollTop,\n\t\t\t\tlinkData.clientRects,\n\t\t\t\ttrue\n\t\t\t) + windowData.scrollTop;\n\t\t}\n\n\t\toffsetTop -= pokeySize;\n\t}\n\n\treturn {\n\t\toffset: {\n\t\t\ttop: offsetTop,\n\t\t\tleft: offsetLeft\n\t\t},\n\t\tflippedX: flippedX,\n\t\tflippedY: flippedY\n\t};\n}\n\n/**\n * Generates a list of declarative CSS classes that represent the layout of\n * the preview.\n *\n * @param {ext.popups.Preview} preview\n * @param {ext.popups.PreviewLayout} layout\n * @return {String[]}\n */\nfunction getClasses( preview, layout ) {\n\tvar classes = [];\n\n\tif ( layout.flippedY ) {\n\t\tclasses.push( 'mwe-popups-fade-in-down' );\n\t} else {\n\t\tclasses.push( 'mwe-popups-fade-in-up' );\n\t}\n\n\tif ( layout.flippedY && layout.flippedX ) {\n\t\tclasses.push( 'flipped_x_y' );\n\t}\n\n\tif ( layout.flippedY && !layout.flippedX ) {\n\t\tclasses.push( 'flipped_y' );\n\t}\n\n\tif ( layout.flippedX && !layout.flippedY ) {\n\t\tclasses.push( 'flipped_x' );\n\t}\n\n\tif ( ( !preview.hasThumbnail || preview.isTall ) && !layout.flippedY ) {\n\t\tclasses.push( 'mwe-popups-no-image-tri' );\n\t}\n\n\tif ( ( preview.hasThumbnail && !preview.isTall ) && !layout.flippedY ) {\n\t\tclasses.push( 'mwe-popups-image-tri' );\n\t}\n\n\tif ( preview.isTall ) {\n\t\tclasses.push( 'mwe-popups-is-tall' );\n\t} else {\n\t\tclasses.push( 'mwe-popups-is-not-tall' );\n\t}\n\n\treturn classes;\n}\n\n/**\n * Lays out the preview given the layout.\n *\n * If the preview should be oriented differently, then the pokey is updated,\n * e.g. if the preview should be flipped vertically, then the pokey is\n * removed.\n *\n * If the thumbnail is landscape and isn't the full height of the thumbnail\n * container, then pull the extract up to keep whitespace consistent across\n * previews.\n *\n * @param {ext.popups.Preview} preview\n * @param {ext.popups.PreviewLayout} layout\n * @param {string[]} classes class names used for layout out the preview\n * @param {number} predefinedLandscapeImageHeight landscape image height\n * @param {number} pokeySize\n */\nfunction layoutPreview( preview, layout, classes, predefinedLandscapeImageHeight, pokeySize ) {\n\tvar popup = preview.el,\n\t\tisTall = preview.isTall,\n\t\thasThumbnail = preview.hasThumbnail,\n\t\tthumbnail = preview.thumbnail,\n\t\tflippedY = layout.flippedY,\n\t\tflippedX = layout.flippedX,\n\t\toffsetTop = layout.offset.top;\n\n\tif (\n\t\t!flippedY && !isTall && hasThumbnail &&\n\t\t\tthumbnail.height < predefinedLandscapeImageHeight\n\t) {\n\t\tpopup.find( '.mwe-popups-extract' ).css(\n\t\t\t'margin-top',\n\t\t\tthumbnail.height - pokeySize\n\t\t);\n\t}\n\n\tpopup.addClass( classes.join( ' ' ) );\n\n\tif ( flippedY ) {\n\t\toffsetTop -= popup.outerHeight();\n\t}\n\n\tpopup.css( {\n\t\ttop: offsetTop,\n\t\tleft: layout.offset.left + 'px'\n\t} );\n\n\tif ( flippedY && hasThumbnail ) {\n\t\tpopup.find( 'image' )[ 0 ]\n\t\t\t.removeAttribute( 'clip-path' );\n\t}\n\n\tif ( flippedY && flippedX && hasThumbnail && isTall ) {\n\t\tpopup.find( 'image' )[ 0 ]\n\t\t\t.setAttribute( 'clip-path', 'url(#mwe-popups-landscape-mask-flip)' );\n\t}\n\n\tif ( flippedX && !flippedY && hasThumbnail && !isTall ) {\n\t\tpopup.find( 'image' )[ 0 ]\n\t\t\t.setAttribute( 'clip-path', 'url(#mwe-popups-mask-flip)' );\n\t}\n\n\tif ( flippedX && !flippedY && hasThumbnail && isTall ) {\n\t\tpopup.removeClass( 'mwe-popups-no-image-tri' )\n\t\t\t.find( 'image' )[ 0 ]\n\t\t\t.setAttribute( 'clip-path', 'url(#mwe-popups-landscape-mask)' );\n\t}\n}\n\n/**\n * Given the rectangular box(es) find the 'y' boundary of the closest\n * rectangle to the point 'y'. The point 'y' is the location of the mouse\n * on the 'y' axis and the rectangular box(es) are the borders of the\n * element over which the mouse is located. There will be more than one\n * rectangle in case the element spans multiple lines.\n *\n * In the majority of cases the mouse pointer will be inside a rectangle.\n * However, some browsers (i.e. Chrome) trigger a hover action even when\n * the mouse pointer is just outside a bounding rectangle. That's why\n * we need to look at all rectangles and not just the rectangle that\n * encloses the point.\n *\n * @private\n * @param {Number} y the point for which the closest location is being\n * looked for\n * @param {ClientRectList} rects list of rectangles defined by four edges\n * @param {Boolean} [isTop] should the resulting rectangle's top 'y'\n * boundary be returned. By default the bottom 'y' value is returned.\n * @return {Number}\n */\nfunction getClosestYPosition( y, rects, isTop ) {\n\tvar result,\n\t\tdeltaY,\n\t\tminY = null;\n\n\t$.each( rects, function ( i, rect ) {\n\t\tdeltaY = Math.abs( y - rect.top + y - rect.bottom );\n\n\t\tif ( minY === null || minY > deltaY ) {\n\t\t\tminY = deltaY;\n\t\t\t// Make sure the resulting point is at or outside the rectangle\n\t\t\t// boundaries.\n\t\t\tresult = ( isTop ) ? Math.floor( rect.top ) : Math.ceil( rect.bottom );\n\t\t}\n\t} );\n\n\treturn result;\n}\n\n\n/***/ }),\n\n/***/ \"./src/ui/settingsDialog.js\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony export (immutable) */ __webpack_exports__[\"a\"] = createSettingsDialogRenderer;\n/**\n * @module settingsDialog\n */\n\nvar mw = window.mediaWiki,\n\t$ = jQuery;\n\n/**\n * Creates a render function that will create the settings dialog and return\n * a set of methods to operate on it\n * @returns {Function} render function\n */\nfunction createSettingsDialogRenderer() {\n\n\t/**\n\t * Cached settings dialog\n\t *\n\t * @type {jQuery}\n\t */\n\tvar $dialog,\n\t\t/**\n\t\t * Cached settings overlay\n\t\t *\n\t\t * @type {jQuery}\n\t\t */\n\t\t$overlay;\n\n\t/**\n\t * Renders the relevant form and labels in the settings dialog\n\t * @param {Object} boundActions\n\t * @returns {Object} object with methods to affect the rendered UI\n\t */\n\treturn function ( boundActions ) {\n\n\t\tif ( !$dialog ) {\n\t\t\t$dialog = createSettingsDialog();\n\t\t\t$overlay = $( '<div>' ).addClass( 'mwe-popups-overlay' );\n\n\t\t\t// Setup event bindings\n\n\t\t\t$dialog.find( '.save' ).click( function () {\n\t\t\t\t// Find the selected value (simple|advanced|off)\n\t\t\t\tvar selected = getSelectedSetting( $dialog ),\n\t\t\t\t\t// Only simple means enabled, advanced is disabled in favor of\n\t\t\t\t\t// NavPops and off means disabled.\n\t\t\t\t\tenabled = selected === 'simple';\n\n\t\t\t\tboundActions.saveSettings( enabled );\n\t\t\t} );\n\t\t\t$dialog.find( '.close, .okay' ).click( boundActions.hideSettings );\n\t\t}\n\n\t\treturn {\n\t\t\t/**\n\t\t\t * Append the dialog and overlay to a DOM element\n\t\t\t * @param {HTMLElement} el\n\t\t\t */\n\t\t\tappendTo: function ( el ) {\n\t\t\t\t$overlay.appendTo( el );\n\t\t\t\t$dialog.appendTo( el );\n\t\t\t},\n\n\t\t\t/**\n\t\t\t * Show the settings element and position it correctly\n\t\t\t */\n\t\t\tshow: function () {\n\t\t\t\tvar h = $( window ).height(),\n\t\t\t\t\tw = $( window ).width();\n\n\t\t\t\t$overlay.show();\n\n\t\t\t\t// FIXME: Should recalc on browser resize\n\t\t\t\t$dialog\n\t\t\t\t\t.show()\n\t\t\t\t\t.css( 'left', ( w - $dialog.outerWidth( true ) ) / 2 )\n\t\t\t\t\t.css( 'top', ( h - $dialog.outerHeight( true ) ) / 2 );\n\t\t\t},\n\n\t\t\t/**\n\t\t\t * Hide the settings dialog.\n\t\t\t */\n\t\t\thide: function () {\n\t\t\t\t$overlay.hide();\n\t\t\t\t$dialog.hide();\n\t\t\t},\n\n\t\t\t/**\n\t\t\t * Toggle the help dialog on or off\n\t\t\t * @param {Boolean} visible if you want to show or hide the help dialog\n\t\t\t */\n\t\t\ttoggleHelp: function ( visible ) {\n\t\t\t\ttoggleHelp( $dialog, visible );\n\t\t\t},\n\n\t\t\t/**\n\t\t\t * Update the form depending on the enabled flag\n\t\t\t *\n\t\t\t * If false and no navpops, then checks 'off'\n\t\t\t * If true, then checks 'on'\n\t\t\t * If false, and there are navpops, then checks 'advanced'\n\t\t\t *\n\t\t\t * @param {Boolean} enabled if page previews are enabled\n\t\t\t */\n\t\t\tsetEnabled: function ( enabled ) {\n\t\t\t\tvar name = 'off';\n\t\t\t\tif ( enabled ) {\n\t\t\t\t\tname = 'simple';\n\t\t\t\t} else if ( isNavPopupsEnabled() ) {\n\t\t\t\t\tname = 'advanced';\n\t\t\t\t}\n\n\t\t\t\t// Check the appropiate radio button\n\t\t\t\t$dialog.find( '#mwe-popups-settings-' + name )\n\t\t\t\t\t.prop( 'checked', true );\n\t\t\t}\n\t\t};\n\t};\n}\n\n/**\n * Create the settings dialog\n *\n * @return {jQuery} settings dialog\n */\nfunction createSettingsDialog() {\n\tvar $el,\n\t\tpath = mw.config.get( 'wgExtensionAssetsPath' ) + '/Popups/resources/ext.popups/images/',\n\t\tchoices = [\n\t\t\t{\n\t\t\t\tid: 'simple',\n\t\t\t\tname: mw.msg( 'popups-settings-option-simple' ),\n\t\t\t\tdescription: mw.msg( 'popups-settings-option-simple-description' ),\n\t\t\t\timage: path + 'hovercard.svg',\n\t\t\t\tisChecked: true\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'advanced',\n\t\t\t\tname: mw.msg( 'popups-settings-option-advanced' ),\n\t\t\t\tdescription: mw.msg( 'popups-settings-option-advanced-description' ),\n\t\t\t\timage: path + 'navpop.svg'\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'off',\n\t\t\t\tname: mw.msg( 'popups-settings-option-off' )\n\t\t\t}\n\t\t];\n\n\tif ( !isNavPopupsEnabled() ) {\n\t\t// remove the advanced option\n\t\tchoices.splice( 1, 1 );\n\t}\n\n\t// render the template\n\t$el = mw.template.get( 'ext.popups', 'settings.mustache' ).render( {\n\t\theading: mw.msg( 'popups-settings-title' ),\n\t\tcloseLabel: mw.msg( 'popups-settings-cancel' ),\n\t\tsaveLabel: mw.msg( 'popups-settings-save' ),\n\t\thelpText: mw.msg( 'popups-settings-help' ),\n\t\tokLabel: mw.msg( 'popups-settings-help-ok' ),\n\t\tdescriptionText: mw.msg( 'popups-settings-description' ),\n\t\tchoices: choices\n\t} );\n\n\treturn $el;\n}\n\n/**\n * Get the selected value on the radio button\n *\n * @param {jQuery.Object} $el the element to extract the setting from\n * @return {String} Which should be (simple|advanced|off)\n */\nfunction getSelectedSetting( $el ) {\n\treturn $el.find(\n\t\t'input[name=mwe-popups-setting]:checked, #mwe-popups-settings'\n\t).val();\n}\n\n/**\n * Toggles the visibility between a form and the help\n * @param {jQuery.Object} $el element that contains form and help\n * @param {Boolean} visible if the help should be visible, or the form\n */\nfunction toggleHelp( $el, visible ) {\n\tvar $dialog = $( '#mwe-popups-settings' ),\n\t\tformSelectors = 'main, .save, .close',\n\t\thelpSelectors = '.mwe-popups-settings-help, .okay';\n\n\tif ( visible ) {\n\t\t$dialog.find( formSelectors ).hide();\n\t\t$dialog.find( helpSelectors ).show();\n\t} else {\n\t\t$dialog.find( formSelectors ).show();\n\t\t$dialog.find( helpSelectors ).hide();\n\t}\n}\n\n/**\n * Checks if the NavigationPopups gadget is enabled by looking at the global\n * variables\n * @returns {Boolean} if navpops was found to be enabled\n */\nfunction isNavPopupsEnabled() {\n\t/* global pg: false*/\n\treturn typeof pg !== 'undefined' && pg.fn.disablePopups !== undefined;\n}\n\n\n/***/ }),\n\n/***/ \"./src/userSettings.js\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony export (immutable) */ __webpack_exports__[\"a\"] = createUserSettings;\n/**\n * @module userSettings\n */\n\n/**\n * @interface UserSettings\n *\n * @global\n */\n\nvar IS_ENABLED_KEY = 'mwe-popups-enabled',\n\tPREVIEW_COUNT_KEY = 'ext.popups.core.previewCount';\n\n/**\n * Creates an object whose methods encapsulate all interactions with the UA's\n * storage.\n *\n * @param {Object} storage The `mw.storage` singleton instance\n *\n * @return {UserSettings}\n */\nfunction createUserSettings( storage ) {\n\treturn {\n\n\t\t/**\n\t\t * Gets whether the user has previously enabled Page Previews.\n\t\t *\n\t\t * N.B. that if the user hasn't previously enabled or disabled Page\n\t\t * Previews, i.e. userSettings.setIsEnabled(true), then they are treated as\n\t\t * if they have enabled them.\n\t\t *\n\t\t * @function\n\t\t * @name UserSettings#getIsEnabled\n\t\t * @return {Boolean}\n\t\t */\n\t\tgetIsEnabled: function () {\n\t\t\treturn storage.get( IS_ENABLED_KEY ) !== '0';\n\t\t},\n\n\t\t/**\n\t\t * Sets whether the user has enabled Page Previews.\n\t\t *\n\t\t * @function\n\t\t * @name UserSettings#setIsEnabled\n\t\t * @param {Boolean} isEnabled\n\t\t */\n\t\tsetIsEnabled: function ( isEnabled ) {\n\t\t\tstorage.set( IS_ENABLED_KEY, isEnabled ? '1' : '0' );\n\t\t},\n\n\t\t/**\n\t\t * Gets whether the user has previously enabled **or disabled** Page\n\t\t * Previews.\n\t\t *\n\t\t * @function\n\t\t * @name UserSettings#hasIsEnabled\n\t\t * @return {Boolean}\n\t\t */\n\t\thasIsEnabled: function () {\n\t\t\tvar value = storage.get( IS_ENABLED_KEY );\n\n\t\t\treturn Boolean( value ) !== false;\n\t\t},\n\n\t\t/**\n\t\t * Gets the number of previews that the user has seen.\n\t\t *\n\t\t * If the storage isn't available, then -1 is returned.\n\t\t * If the value in storage is not a number it will override stored value to 0\n\t\t *\n\t\t * @function\n\t\t * @name UserSettings#getPreviewCount\n\t\t * @return {Number}\n\t\t */\n\t\tgetPreviewCount: function () {\n\t\t\tvar result = storage.get( PREVIEW_COUNT_KEY ), count;\n\n\t\t\tif ( result === false ) {\n\t\t\t\treturn -1;\n\t\t\t} else if ( result === null ) {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tcount = parseInt( result, 10 );\n\n\t\t\t// stored number is not a zero, override it to zero and store new value\n\t\t\tif ( isNaN( count ) ) {\n\t\t\t\tcount = 0;\n\t\t\t\tthis.setPreviewCount( count );\n\t\t\t}\n\t\t\treturn count;\n\t\t},\n\n\t\t/**\n\t\t * Sets the number of previews that the user has seen.\n\t\t *\n\t\t * @function\n\t\t * @name UserSettings#setPreviewCount\n\t\t * @param {Number} count\n\t\t */\n\t\tsetPreviewCount: function ( count ) {\n\t\t\tstorage.set( PREVIEW_COUNT_KEY, count.toString() );\n\t\t}\n\t};\n}\n\n\n/***/ }),\n\n/***/ \"./src/wait.js\":\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony export (immutable) */ __webpack_exports__[\"a\"] = wait;\n/**\n * @module wait\n */\n\nvar $ = jQuery;\n\n/**\n * Sugar around `window.setTimeout`.\n *\n * @example\n * import wait from './wait';\n *\n * wait( 150 )\n * .then( function () {\n * // Continue processing...\n * } );\n *\n * @param {Number} delay The number of milliseconds to wait\n * @return {jQuery.Promise}\n */\nfunction wait( delay ) {\n\tvar result = $.Deferred();\n\n\tsetTimeout( function () {\n\t\tresult.resolve();\n\t}, delay );\n\n\treturn result.promise();\n}\n\n\n/***/ })\n\n/******/ });\n\n\n// WEBPACK FOOTER //\n// index.js"," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// identity function for calling harmony imports with the correct context\n \t__webpack_require__.i = function(value) { return value; };\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = \"./src/index.js\");\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap c9b1d11267645803e45f","!function(t,e){\"object\"==typeof exports&&\"object\"==typeof module?module.exports=e():\"function\"==typeof define&&define.amd?define([],e):\"object\"==typeof exports?exports.ReduxThunk=e():t.ReduxThunk=e()}(this,function(){return function(t){function e(o){if(n[o])return n[o].exports;var r=n[o]={exports:{},id:o,loaded:!1};return t[o].call(r.exports,r,r.exports,e),r.loaded=!0,r.exports}var n={};return e.m=t,e.c=n,e.p=\"\",e(0)}([function(t,e,n){t.exports=n(1)},function(t,e){\"use strict\";function n(t){return function(e){var n=e.dispatch,o=e.getState;return function(e){return function(r){return\"function\"==typeof r?r(n,o,t):e(r)}}}}e.__esModule=!0;var o=n();o.withExtraArgument=n,e.default=o}])});\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./~/redux-thunk/dist/redux-thunk.min.js\n// module id = ./node_modules/redux-thunk/dist/redux-thunk.min.js\n// module chunks = 0","!function(t,e){\"object\"==typeof exports&&\"object\"==typeof module?module.exports=e():\"function\"==typeof define&&define.amd?define([],e):\"object\"==typeof exports?exports.Redux=e():t.Redux=e()}(this,function(){return function(t){function e(r){if(n[r])return n[r].exports;var o=n[r]={exports:{},id:r,loaded:!1};return t[r].call(o.exports,o,o.exports,e),o.loaded=!0,o.exports}var n={};return e.m=t,e.c=n,e.p=\"\",e(0)}([function(t,e,n){\"use strict\";function r(t){return t&&t.__esModule?t:{\"default\":t}}e.__esModule=!0,e.compose=e.applyMiddleware=e.bindActionCreators=e.combineReducers=e.createStore=void 0;var o=n(2),u=r(o),i=n(7),c=r(i),a=n(6),f=r(a),s=n(5),d=r(s),l=n(1),p=r(l),y=n(3);r(y);e.createStore=u[\"default\"],e.combineReducers=c[\"default\"],e.bindActionCreators=f[\"default\"],e.applyMiddleware=d[\"default\"],e.compose=p[\"default\"]},function(t,e){\"use strict\";function n(){for(var t=arguments.length,e=Array(t),n=0;t>n;n++)e[n]=arguments[n];if(0===e.length)return function(t){return t};if(1===e.length)return e[0];var r=e[e.length-1],o=e.slice(0,-1);return function(){return o.reduceRight(function(t,e){return e(t)},r.apply(void 0,arguments))}}e.__esModule=!0,e[\"default\"]=n},function(t,e,n){\"use strict\";function r(t){return t&&t.__esModule?t:{\"default\":t}}function o(t,e,n){function r(){b===h&&(b=h.slice())}function u(){return v}function c(t){if(\"function\"!=typeof t)throw Error(\"Expected listener to be a function.\");var e=!0;return r(),b.push(t),function(){if(e){e=!1,r();var n=b.indexOf(t);b.splice(n,1)}}}function s(t){if(!(0,i[\"default\"])(t))throw Error(\"Actions must be plain objects. Use custom middleware for async actions.\");if(void 0===t.type)throw Error('Actions may not have an undefined \"type\" property. Have you misspelled a constant?');if(m)throw Error(\"Reducers may not dispatch actions.\");try{m=!0,v=y(v,t)}finally{m=!1}for(var e=h=b,n=0;e.length>n;n++)e[n]();return t}function d(t){if(\"function\"!=typeof t)throw Error(\"Expected the nextReducer to be a function.\");y=t,s({type:f.INIT})}function l(){var t,e=c;return t={subscribe:function(t){function n(){t.next&&t.next(u())}if(\"object\"!=typeof t)throw new TypeError(\"Expected the observer to be an object.\");n();var r=e(n);return{unsubscribe:r}}},t[a[\"default\"]]=function(){return this},t}var p;if(\"function\"==typeof e&&void 0===n&&(n=e,e=void 0),void 0!==n){if(\"function\"!=typeof n)throw Error(\"Expected the enhancer to be a function.\");return n(o)(t,e)}if(\"function\"!=typeof t)throw Error(\"Expected the reducer to be a function.\");var y=t,v=e,h=[],b=h,m=!1;return s({type:f.INIT}),p={dispatch:s,subscribe:c,getState:u,replaceReducer:d},p[a[\"default\"]]=l,p}e.__esModule=!0,e.ActionTypes=void 0,e[\"default\"]=o;var u=n(4),i=r(u),c=n(12),a=r(c),f=e.ActionTypes={INIT:\"@@redux/INIT\"}},function(t,e){\"use strict\";function n(t){\"undefined\"!=typeof console&&\"function\"==typeof console.error&&console.error(t);try{throw Error(t)}catch(e){}}e.__esModule=!0,e[\"default\"]=n},function(t,e,n){function r(t){if(!i(t)||p.call(t)!=c||u(t))return!1;var e=o(t);if(null===e)return!0;var n=d.call(e,\"constructor\")&&e.constructor;return\"function\"==typeof n&&n instanceof n&&s.call(n)==l}var o=n(8),u=n(9),i=n(11),c=\"[object Object]\",a=Function.prototype,f=Object.prototype,s=a.toString,d=f.hasOwnProperty,l=s.call(Object),p=f.toString;t.exports=r},function(t,e,n){\"use strict\";function r(t){return t&&t.__esModule?t:{\"default\":t}}function o(){for(var t=arguments.length,e=Array(t),n=0;t>n;n++)e[n]=arguments[n];return function(t){return function(n,r,o){var i=t(n,r,o),a=i.dispatch,f=[],s={getState:i.getState,dispatch:function(t){return a(t)}};return f=e.map(function(t){return t(s)}),a=c[\"default\"].apply(void 0,f)(i.dispatch),u({},i,{dispatch:a})}}}e.__esModule=!0;var u=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(t[r]=n[r])}return t};e[\"default\"]=o;var i=n(1),c=r(i)},function(t,e){\"use strict\";function n(t,e){return function(){return e(t.apply(void 0,arguments))}}function r(t,e){if(\"function\"==typeof t)return n(t,e);if(\"object\"!=typeof t||null===t)throw Error(\"bindActionCreators expected an object or a function, instead received \"+(null===t?\"null\":typeof t)+'. Did you write \"import ActionCreators from\" instead of \"import * as ActionCreators from\"?');for(var r=Object.keys(t),o={},u=0;r.length>u;u++){var i=r[u],c=t[i];\"function\"==typeof c&&(o[i]=n(c,e))}return o}e.__esModule=!0,e[\"default\"]=r},function(t,e,n){\"use strict\";function r(t){return t&&t.__esModule?t:{\"default\":t}}function o(t,e){var n=e&&e.type,r=n&&'\"'+n+'\"'||\"an action\";return\"Given action \"+r+', reducer \"'+t+'\" returned undefined. To ignore an action, you must explicitly return the previous state.'}function u(t){Object.keys(t).forEach(function(e){var n=t[e],r=n(void 0,{type:c.ActionTypes.INIT});if(void 0===r)throw Error('Reducer \"'+e+'\" returned undefined during initialization. If the state passed to the reducer is undefined, you must explicitly return the initial state. The initial state may not be undefined.');var o=\"@@redux/PROBE_UNKNOWN_ACTION_\"+Math.random().toString(36).substring(7).split(\"\").join(\".\");if(void 0===n(void 0,{type:o}))throw Error('Reducer \"'+e+'\" returned undefined when probed with a random type. '+(\"Don't try to handle \"+c.ActionTypes.INIT+' or other actions in \"redux/*\" ')+\"namespace. They are considered private. Instead, you must return the current state for any unknown actions, unless it is undefined, in which case you must return the initial state, regardless of the action type. The initial state may not be undefined.\")})}function i(t){for(var e=Object.keys(t),n={},r=0;e.length>r;r++){var i=e[r];\"function\"==typeof t[i]&&(n[i]=t[i])}var c,a=Object.keys(n);try{u(n)}catch(f){c=f}return function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},e=arguments[1];if(c)throw c;for(var r=!1,u={},i=0;a.length>i;i++){var f=a[i],s=n[f],d=t[f],l=s(d,e);if(void 0===l){var p=o(f,e);throw Error(p)}u[f]=l,r=r||l!==d}return r?u:t}}e.__esModule=!0,e[\"default\"]=i;var c=n(2),a=n(4),f=(r(a),n(3));r(f)},function(t,e,n){var r=n(10),o=r(Object.getPrototypeOf,Object);t.exports=o},function(t,e){function n(t){var e=!1;if(null!=t&&\"function\"!=typeof t.toString)try{e=!!(t+\"\")}catch(n){}return e}t.exports=n},function(t,e){function n(t,e){return function(n){return t(e(n))}}t.exports=n},function(t,e){function n(t){return!!t&&\"object\"==typeof t}t.exports=n},function(t,e,n){t.exports=n(13)},function(t,e,n){(function(t){\"use strict\";function r(t){return t&&t.__esModule?t:{\"default\":t}}Object.defineProperty(e,\"__esModule\",{value:!0});var o=n(14),u=r(o),i=void 0;void 0!==t?i=t:\"undefined\"!=typeof window&&(i=window);var c=(0,u[\"default\"])(i);e[\"default\"]=c}).call(e,function(){return this}())},function(t,e){\"use strict\";function n(t){var e,n=t.Symbol;return\"function\"==typeof n?n.observable?e=n.observable:(e=n(\"observable\"),n.observable=e):e=\"@@observable\",e}Object.defineProperty(e,\"__esModule\",{value:!0}),e[\"default\"]=n}])});\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./~/redux/dist/redux.min.js\n// module id = ./node_modules/redux/dist/redux.min.js\n// module chunks = 0","/**\n * @module actionTypes\n */\n\nexport default {\n\tBOOT: 'BOOT',\n\tLINK_DWELL: 'LINK_DWELL',\n\tABANDON_START: 'ABANDON_START',\n\tABANDON_END: 'ABANDON_END',\n\tLINK_CLICK: 'LINK_CLICK',\n\tFETCH_START: 'FETCH_START',\n\tFETCH_END: 'FETCH_END',\n\tFETCH_COMPLETE: 'FETCH_COMPLETE',\n\tFETCH_FAILED: 'FETCH_FAILED',\n\tPREVIEW_DWELL: 'PREVIEW_DWELL',\n\tPREVIEW_SHOW: 'PREVIEW_SHOW',\n\tPREVIEW_CLICK: 'PREVIEW_CLICK',\n\tSETTINGS_SHOW: 'SETTINGS_SHOW',\n\tSETTINGS_HIDE: 'SETTINGS_HIDE',\n\tSETTINGS_CHANGE: 'SETTINGS_CHANGE',\n\tEVENT_LOGGED: 'EVENT_LOGGED',\n\tSTATSV_LOGGED: 'STATSV_LOGGED'\n};\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/actionTypes.js\n// module id = ./src/actionTypes.js\n// module chunks = 0","/**\n * @module actions\n */\n\nimport types from './actionTypes';\nimport wait from './wait';\n\nvar $ = jQuery,\n\tmw = window.mediaWiki,\n\n\t// See the following for context around this value.\n\t//\n\t// * https://phabricator.wikimedia.org/T161284\n\t// * https://phabricator.wikimedia.org/T70861#3129780\n\tFETCH_START_DELAY = 150, // ms.\n\n\t// The delay after which a FETCH_COMPLETE action should be dispatched.\n\t//\n\t// If the API endpoint responds faster than 500 ms (or, say, the API\n\t// response is served from the UA's cache), then we introduce a delay of\n\t// 500 - t to make the preview delay consistent to the user.\n\tFETCH_COMPLETE_TARGET_DELAY = 500, // ms.\n\n\tABANDON_END_DELAY = 300; // ms.\n\n/**\n * Mixes in timing information to an action.\n *\n * Warning: the `baseAction` parameter is modified and returned.\n *\n * @param {Object} baseAction\n * @return {Object}\n */\nfunction timedAction( baseAction ) {\n\tbaseAction.timestamp = mw.now();\n\n\treturn baseAction;\n}\n\n/**\n * Represents Page Previews booting.\n *\n * When a Redux store is created, the `@@INIT` action is immediately\n * dispatched to it. To avoid overriding the term, we refer to booting rather\n * than initializing.\n *\n * Page Previews persists critical pieces of information to local storage.\n * Since reading from and writing to local storage are synchronous, Page\n * Previews is booted when the browser is idle (using\n * [`mw.requestIdleCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback))\n * so as not to impact latency-critical events.\n *\n * @param {Boolean} isEnabled See `isEnabled.js`\n * @param {mw.user} user\n * @param {ext.popups.UserSettings} userSettings\n * @param {Function} generateToken\n * @param {mw.Map} config The config of the MediaWiki client-side application,\n * i.e. `mw.config`\n * @returns {Object}\n */\nexport function boot(\n\tisEnabled,\n\tuser,\n\tuserSettings,\n\tgenerateToken,\n\tconfig\n) {\n\tvar editCount = config.get( 'wgUserEditCount' ),\n\t\tpreviewCount = userSettings.getPreviewCount();\n\n\treturn {\n\t\ttype: types.BOOT,\n\t\tisEnabled: isEnabled,\n\t\tisNavPopupsEnabled: config.get( 'wgPopupsConflictsWithNavPopupGadget' ),\n\t\tsessionToken: user.sessionId(),\n\t\tpageToken: generateToken(),\n\t\tpage: {\n\t\t\ttitle: config.get( 'wgTitle' ),\n\t\t\tnamespaceID: config.get( 'wgNamespaceNumber' ),\n\t\t\tid: config.get( 'wgArticleId' )\n\t\t},\n\t\tuser: {\n\t\t\tisAnon: user.isAnon(),\n\t\t\teditCount: editCount,\n\t\t\tpreviewCount: previewCount\n\t\t}\n\t};\n}\n\n/**\n * Represents Page Previews fetching data via the gateway.\n *\n * @param {Gateway} gateway\n * @param {mw.Title} title\n * @param {Element} el\n * @param {String} token The unique token representing the link interaction that\n * triggered the fetch\n * @return {Redux.Thunk}\n */\nexport function fetch( gateway, title, el, token ) {\n\tvar titleText = title.getPrefixedDb(),\n\t\tnamespaceID = title.namespace;\n\n\treturn function ( dispatch ) {\n\t\tvar request;\n\n\t\tdispatch( timedAction( {\n\t\t\ttype: types.FETCH_START,\n\t\t\tel: el,\n\t\t\ttitle: titleText,\n\t\t\tnamespaceID: namespaceID\n\t\t} ) );\n\n\t\trequest = gateway.getPageSummary( titleText )\n\t\t\t.then( function ( result ) {\n\t\t\t\tdispatch( timedAction( {\n\t\t\t\t\ttype: types.FETCH_END,\n\t\t\t\t\tel: el\n\t\t\t\t} ) );\n\n\t\t\t\treturn result;\n\t\t\t} )\n\t\t\t// FIXME: Convert to Promises A/A+ when \"T124742: Upgrade to jQuery 3\" is\n\t\t\t// fully rolled out by changing fail to catch, and re-throwing the error\n\t\t\t// to keep the promise in a rejected state.\n\t\t\t.fail( function () {\n\t\t\t\tdispatch( {\n\t\t\t\t\ttype: types.FETCH_FAILED,\n\t\t\t\t\tel: el\n\t\t\t\t} );\n\t\t\t} );\n\n\t\treturn $.when( request, wait( FETCH_COMPLETE_TARGET_DELAY - FETCH_START_DELAY ) )\n\t\t\t.then( function ( result ) {\n\t\t\t\tdispatch( timedAction( {\n\t\t\t\t\ttype: types.FETCH_COMPLETE,\n\t\t\t\t\tel: el,\n\t\t\t\t\tresult: result,\n\t\t\t\t\ttoken: token\n\t\t\t\t} ) );\n\t\t\t} );\n\t};\n}\n\n/**\n * Represents the user dwelling on a link, either by hovering over it with\n * their mouse or by focussing it using their keyboard or an assistive device.\n *\n * @param {mw.Title} title\n * @param {Element} el\n * @param {Event} event\n * @param {Gateway} gateway\n * @param {Function} generateToken\n * @return {Redux.Thunk}\n */\nexport function linkDwell( title, el, event, gateway, generateToken ) {\n\tvar token = generateToken(),\n\t\ttitleText = title.getPrefixedDb(),\n\t\tnamespaceID = title.namespace;\n\n\treturn function ( dispatch, getState ) {\n\t\tvar action = timedAction( {\n\t\t\ttype: types.LINK_DWELL,\n\t\t\tel: el,\n\t\t\tevent: event,\n\t\t\ttoken: token,\n\t\t\ttitle: titleText,\n\t\t\tnamespaceID: namespaceID\n\t\t} );\n\n\t\t// Has the new generated token been accepted?\n\t\tfunction isNewInteraction() {\n\t\t\treturn getState().preview.activeToken === token;\n\t\t}\n\n\t\tdispatch( action );\n\n\t\tif ( !isNewInteraction() ) {\n\t\t\treturn;\n\t\t}\n\n\t\twait( FETCH_START_DELAY )\n\t\t\t.then( function () {\n\t\t\t\tvar previewState = getState().preview;\n\n\t\t\t\tif ( previewState.enabled && isNewInteraction() ) {\n\t\t\t\t\tdispatch( fetch( gateway, title, el, token ) );\n\t\t\t\t}\n\t\t\t} );\n\t};\n}\n\n/**\n * Represents the user abandoning a link, either by moving their mouse away\n * from it or by shifting focus to another UI element using their keyboard or\n * an assistive device, or abandoning a preview by moving their mouse away\n * from it.\n *\n * @return {Redux.Thunk}\n */\nexport function abandon() {\n\treturn function ( dispatch, getState ) {\n\t\tvar token = getState().preview.activeToken;\n\n\t\tif ( !token ) {\n\t\t\treturn;\n\t\t}\n\n\t\tdispatch( timedAction( {\n\t\t\ttype: types.ABANDON_START,\n\t\t\ttoken: token\n\t\t} ) );\n\n\t\twait( ABANDON_END_DELAY )\n\t\t\t.then( function () {\n\t\t\t\tdispatch( {\n\t\t\t\t\ttype: types.ABANDON_END,\n\t\t\t\t\ttoken: token\n\t\t\t\t} );\n\t\t\t} );\n\t};\n}\n\n/**\n * Represents the user clicking on a link with their mouse, keyboard, or an\n * assistive device.\n *\n * @param {Element} el\n * @return {Object}\n */\nexport function linkClick( el ) {\n\treturn timedAction( {\n\t\ttype: types.LINK_CLICK,\n\t\tel: el\n\t} );\n}\n\n/**\n * Represents the user dwelling on a preview with their mouse.\n *\n * @return {Object}\n */\nexport function previewDwell() {\n\treturn {\n\t\ttype: types.PREVIEW_DWELL\n\t};\n}\n\n/**\n * Represents a preview being shown to the user.\n *\n * This action is dispatched by the `./changeListeners/render.js` change\n * listener.\n *\n * @param {String} token\n * @return {Object}\n */\nexport function previewShow( token ) {\n\treturn timedAction( {\n\t\ttype: types.PREVIEW_SHOW,\n\t\ttoken: token\n\t} );\n}\n\n/**\n * Represents the user clicking either the \"Enable previews\" footer menu link,\n * or the \"cog\" icon that's present on each preview.\n *\n * @return {Object}\n */\nexport function showSettings() {\n\treturn {\n\t\ttype: types.SETTINGS_SHOW\n\t};\n}\n\n/**\n * Represents the user closing the settings dialog and saving their settings.\n *\n * @return {Object}\n */\nexport function hideSettings() {\n\treturn {\n\t\ttype: types.SETTINGS_HIDE\n\t};\n}\n\n/**\n * Represents the user saving their settings.\n *\n * N.B. This action returns a Redux.Thunk not because it needs to perform\n * asynchronous work, but because it needs to query the global state for the\n * current enabled state. In order to keep the enabled state in a single\n * place (the preview reducer), we query it and dispatch it as `wasEnabled`\n * so that other reducers (like settings) can act on it without having to\n * duplicate the `enabled` state locally.\n * See doc/adr/0003-keep-enabled-state-only-in-preview-reducer.md for more\n * details.\n *\n * @param {Boolean} enabled if previews are enabled or not\n * @return {Redux.Thunk}\n */\nexport function saveSettings( enabled ) {\n\treturn function ( dispatch, getState ) {\n\t\tdispatch( {\n\t\t\ttype: types.SETTINGS_CHANGE,\n\t\t\twasEnabled: getState().preview.enabled,\n\t\t\tenabled: enabled\n\t\t} );\n\t};\n}\n\n/**\n * Represents the queued event being logged `changeListeners/eventLogging.js`\n * change listener.\n *\n * @param {Object} event\n * @return {Object}\n */\nexport function eventLogged( event ) {\n\treturn {\n\t\ttype: types.EVENT_LOGGED,\n\t\tevent: event\n\t};\n}\n\n/**\n * Represents the queued statsv event being logged.\n * See `mw.popups.changeListeners.statsv` change listener.\n *\n * @return {Object}\n */\nexport function statsvLogged() {\n\treturn {\n\t\ttype: types.STATSV_LOGGED\n\t};\n}\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/actions.js\n// module id = ./src/actions.js\n// module chunks = 0","/**\n * @module changeListener\n */\n\n/**\n * @typedef {Function} ext.popups.ChangeListener\n * @param {Object} prevState The previous state\n * @param {Object} state The current state\n */\n\n/**\n * Registers a change listener, which is bound to the\n * [store](http://redux.js.org/docs/api/Store.html).\n *\n * A change listener is a function that is only invoked when the state in the\n * [store](http://redux.js.org/docs/api/Store.html) changes. N.B. that there\n * may not be a 1:1 correspondence with actions being dispatched to the store\n * and the state in the store changing.\n *\n * See [Store#subscribe](http://redux.js.org/docs/api/Store.html#subscribe)\n * for more information about what change listeners may and may not do.\n *\n * @param {Redux.Store} store\n * @param {ext.popups.ChangeListener} callback\n */\nexport default function registerChangeListener( store, callback ) {\n\t// This function is based on the example in [the documentation for\n\t// Store#subscribe](http://redux.js.org/docs/api/Store.html#subscribe),\n\t// which was written by Dan Abramov.\n\n\tvar state;\n\n\tstore.subscribe( function () {\n\t\tvar prevState = state;\n\n\t\tstate = store.getState();\n\n\t\tif ( prevState !== state ) {\n\t\t\tcallback( prevState, state );\n\t\t}\n\t} );\n}\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/changeListener.js\n// module id = ./src/changeListener.js\n// module chunks = 0","/**\n * @module changeListeners/eventLogging\n */\n\nvar $ = jQuery;\n\n/**\n * Creates an instance of the event logging change listener.\n *\n * When an event is enqueued it'll be logged using the schema. Since it's the\n * responsibility of Event Logging (and the UA) to deliver logged events,\n * `EVENT_LOGGED` is immediately dispatched rather than waiting for some\n * indicator of completion.\n *\n * @param {Object} boundActions\n * @param {EventTracker} eventLoggingTracker\n * @return {ext.popups.ChangeListener}\n */\nexport default function eventLogging( boundActions, eventLoggingTracker ) {\n\treturn function ( _, state ) {\n\t\tvar eventLogging = state.eventLogging,\n\t\t\tevent = eventLogging.event;\n\n\t\tif ( !event ) {\n\t\t\treturn;\n\t\t}\n\n\t\tevent = $.extend( true, {}, eventLogging.baseData, event );\n\t\teventLoggingTracker( 'event.Popups', event );\n\t\t// Dispatch the eventLogged action so that the state tree can be\n\t\t// cleared/updated.\n\t\tboundActions.eventLogged( event );\n\t};\n}\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/changeListeners/eventLogging.js\n// module id = ./src/changeListeners/eventLogging.js\n// module chunks = 0","/**\n * @module changeListeners/footerLink\n */\n\nvar mw = window.mediaWiki,\n\t$ = jQuery;\n\n/**\n * Creates the link element and appends it to the footer element.\n *\n * The following elements are considered to be the footer element (highest\n * priority to lowest):\n *\n * # `#footer-places`\n * # `#f-list`\n * # The parent element of `#footer li`, which is either an `ol` or `ul`.\n *\n * @return {jQuery} The link element\n */\nfunction createFooterLink() {\n\tvar $link = $( '<li>' ).append(\n\t\t\t$( '<a>' )\n\t\t\t\t.attr( 'href', '#' )\n\t\t\t\t.text( mw.message( 'popups-settings-enable' ).text() )\n\t\t),\n\t\t$footer;\n\n\t// As yet, we don't know whether the link should be visible.\n\t$link.hide();\n\n\t// From https://en.wikipedia.org/wiki/MediaWiki:Gadget-ReferenceTooltips.js,\n\t// which was written by Yair rand <https://en.wikipedia.org/wiki/User:Yair_rand>.\n\t$footer = $( '#footer-places, #f-list' );\n\n\tif ( $footer.length === 0 ) {\n\t\t$footer = $( '#footer li' ).parent();\n\t}\n\n\t$footer.append( $link );\n\n\treturn $link;\n}\n\n/**\n * Creates an instance of the footer link change listener.\n *\n * The change listener covers the following behaviour:\n *\n * * The \"Enable previews\" link (the \"link\") is appended to the footer menu\n * (see `createFooterLink` above).\n * * When Page Previews are disabled, then the link is shown; otherwise, the\n * link is hidden.\n * * When the user clicks the link, then the `showSettings` bound action\n * creator is called.\n *\n * @param {Object} boundActions\n * @return {ext.popups.ChangeListener}\n */\nexport default function footerLink( boundActions ) {\n\tvar $footerLink;\n\n\treturn function ( prevState, state ) {\n\t\tif ( $footerLink === undefined ) {\n\t\t\t$footerLink = createFooterLink();\n\t\t\t$footerLink.click( function ( e ) {\n\t\t\t\te.preventDefault();\n\t\t\t\tboundActions.showSettings();\n\t\t\t} );\n\t\t}\n\n\t\tif ( state.settings.shouldShowFooterLink ) {\n\t\t\t$footerLink.show();\n\t\t} else {\n\t\t\t$footerLink.hide();\n\t\t}\n\t};\n}\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/changeListeners/footerLink.js\n// module id = ./src/changeListeners/footerLink.js\n// module chunks = 0","import footerLink from './footerLink';\nimport eventLogging from './eventLogging';\nimport linkTitle from './linkTitle';\nimport render from './render';\nimport settings from './settings';\nimport statsv from './statsv';\nimport syncUserSettings from './syncUserSettings';\n\nexport default {\n\tfooterLink: footerLink,\n\teventLogging: eventLogging,\n\tlinkTitle: linkTitle,\n\trender: render,\n\tsettings: settings,\n\tstatsv: statsv,\n\tsyncUserSettings: syncUserSettings\n};\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/changeListeners/index.js\n// module id = ./src/changeListeners/index.js\n// module chunks = 0","var $ = jQuery;\n\n/**\n * Creates an instance of the link title change listener.\n *\n * While the user dwells on a link, then it becomes the active link. The\n * change listener will remove a link's `title` attribute while it's the\n * active link.\n *\n * @return {ext.popups.ChangeListener}\n */\nexport default function linkTitle() {\n\tvar title;\n\n\t/**\n\t * Destroys the title attribute of the element, storing its value in local\n\t * state so that it can be restored later (see `restoreTitleAttr`).\n\t *\n\t * @param {Element} el\n\t */\n\tfunction destroyTitleAttr( el ) {\n\t\tvar $el = $( el );\n\n\t\t// Has the user dwelled on a link? If we've already removed its title\n\t\t// attribute, then NOOP.\n\t\tif ( title ) {\n\t\t\treturn;\n\t\t}\n\n\t\ttitle = $el.attr( 'title' );\n\n\t\t$el.attr( 'title', '' );\n\t}\n\n\t/**\n\t * Restores the title attribute of the element.\n\t *\n\t * @param {Element} el\n\t */\n\tfunction restoreTitleAttr( el ) {\n\t\t$( el ).attr( 'title', title );\n\n\t\ttitle = undefined;\n\t}\n\n\treturn function ( prevState, state ) {\n\t\tvar hasPrevActiveLink = prevState && prevState.preview.activeLink;\n\n\t\tif ( !state.preview.enabled ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( hasPrevActiveLink ) {\n\n\t\t\t// Has the user dwelled on a link immediately after abandoning another\n\t\t\t// (remembering that the ABANDON_END action is delayed by\n\t\t\t// ~10e2 ms).\n\t\t\tif ( prevState.preview.activeLink !== state.preview.activeLink ) {\n\t\t\t\trestoreTitleAttr( prevState.preview.activeLink );\n\t\t\t}\n\t\t}\n\n\t\tif ( state.preview.activeLink ) {\n\t\t\tdestroyTitleAttr( state.preview.activeLink );\n\t\t}\n\t};\n}\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/changeListeners/linkTitle.js\n// module id = ./src/changeListeners/linkTitle.js\n// module chunks = 0","import * as renderer from '../ui/renderer';\n\n/**\n * Creates an instance of the render change listener.\n *\n * FIXME: Remove hard coupling with renderer, inject it as a parameter\n * * Wire it up in index.js\n * * Fix tests to remove require mocking\n *\n * @param {ext.popups.PreviewBehavior} previewBehavior\n * @return {ext.popups.ChangeListener}\n */\nexport default function render( previewBehavior ) {\n\tvar preview;\n\n\treturn function ( prevState, state ) {\n\t\tif ( state.preview.shouldShow && !preview ) {\n\t\t\tpreview = renderer.render( state.preview.fetchResponse );\n\t\t\tpreview.show(\n\t\t\t\tstate.preview.activeEvent,\n\t\t\t\tpreviewBehavior,\n\t\t\t\tstate.preview.activeToken\n\t\t\t\t);\n\t\t} else if ( !state.preview.shouldShow && preview ) {\n\t\t\tpreview.hide();\n\t\t\tpreview = undefined;\n\t\t}\n\t};\n}\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/changeListeners/render.js\n// module id = ./src/changeListeners/render.js\n// module chunks = 0","/**\n * Creates an instance of the settings change listener.\n *\n * @param {Object} boundActions\n * @param {Object} render function that renders a jQuery el with the settings\n * @return {ext.popups.ChangeListener}\n */\nexport default function settings( boundActions, render ) {\n\tvar settings;\n\n\treturn function ( prevState, state ) {\n\t\tif ( !prevState ) {\n\t\t\t// Nothing to do on initialization\n\t\t\treturn;\n\t\t}\n\n\t\t// Update global modal visibility\n\t\tif (\n\t\t\tprevState.settings.shouldShow === false &&\n\t\t\tstate.settings.shouldShow === true\n\t\t) {\n\t\t\t// Lazily instantiate the settings UI\n\t\t\tif ( !settings ) {\n\t\t\t\tsettings = render( boundActions );\n\t\t\t\tsettings.appendTo( document.body );\n\t\t\t}\n\n\t\t\t// Update the UI settings with the current settings\n\t\t\tsettings.setEnabled( state.preview.enabled );\n\n\t\t\tsettings.show();\n\t\t} else if (\n\t\t\tprevState.settings.shouldShow === true &&\n\t\t\tstate.settings.shouldShow === false\n\t\t) {\n\t\t\tsettings.hide();\n\t\t}\n\n\t\t// Update help visibility\n\t\tif ( prevState.settings.showHelp !== state.settings.showHelp ) {\n\t\t\tsettings.toggleHelp( state.settings.showHelp );\n\t\t}\n\t};\n}\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/changeListeners/settings.js\n// module id = ./src/changeListeners/settings.js\n// module chunks = 0","/**\n * Creates an instance of the statsv change listener.\n *\n * The listener will log events to StatsD via the [the \"StatsD timers and\n * counters\" analytics event protocol][0].\n *\n * [0]: https://github.com/wikimedia/mediawiki-extensions-WikimediaEvents/blob/29c864a0/modules/ext.wikimediaEvents.statsd.js\n *\n * @param {Object} boundActions\n * @param {EventTracker} track\n * @return {ext.popups.ChangeListener}\n */\nexport default function statsv( boundActions, track ) {\n\treturn function ( _, state ) {\n\t\tvar statsv = state.statsv;\n\n\t\tif ( statsv.action ) {\n\t\t\ttrack( statsv.action, statsv.data );\n\n\t\t\tboundActions.statsvLogged();\n\t\t}\n\t};\n}\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/changeListeners/statsv.js\n// module id = ./src/changeListeners/statsv.js\n// module chunks = 0","/**\n * @module changeListeners/syncUserSettings\n */\n\n/**\n * Creates an instance of the user settings sync change listener.\n *\n * This change listener syncs certain parts of the state tree to user\n * settings when they change.\n *\n * Used for:\n *\n * * Enabled state: If the previews are enabled or disabled.\n * * Preview count: When the user dwells on a link for long enough that\n * a preview is shown, then their preview count will be incremented (see\n * `reducers/eventLogging.js`, and is persisted to local storage.\n *\n * @param {ext.popups.UserSettings} userSettings\n * @return {ext.popups.ChangeListener}\n */\nexport default function syncUserSettings( userSettings ) {\n\n\treturn function ( prevState, state ) {\n\n\t\tsyncIfChanged(\n\t\t\tprevState, state, 'eventLogging', 'previewCount',\n\t\t\tuserSettings.setPreviewCount\n\t\t);\n\t\tsyncIfChanged(\n\t\t\tprevState, state, 'preview', 'enabled',\n\t\t\tuserSettings.setIsEnabled\n\t\t);\n\n\t};\n}\n\n/**\n * Given a state tree, reducer and property, safely return the value of the\n * property if the reducer and property exist\n * @param {Object} state tree\n * @param {String} reducer key to access on the state tree\n * @param {String} prop key to access on the reducer key of the state tree\n * @return {*}\n */\nfunction get( state, reducer, prop ) {\n\treturn state[ reducer ] && state[ reducer ][ prop ];\n}\n\n/**\n * Calls a sync function if the property prop on the property reducer on\n * the state trees has changed value.\n * @param {Object} prevState\n * @param {Object} state\n * @param {String} reducer key to access on the state tree\n * @param {String} prop key to access on the reducer key of the state tree\n * @param {Function} sync function to be called with the newest value if\n * changed\n */\nfunction syncIfChanged( prevState, state, reducer, prop, sync ) {\n\tvar current = get( state, reducer, prop );\n\tif ( prevState && ( get( prevState, reducer, prop ) !== current ) ) {\n\t\tsync( current );\n\t}\n}\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/changeListeners/syncUserSettings.js\n// module id = ./src/changeListeners/syncUserSettings.js\n// module chunks = 0","/**\n * @module constants\n */\nvar $ = jQuery,\n\t// If bracketedDevicePixelRatio is not available default to 1 (in tests for\n\t// example)\n\tpixelRatio = $.bracketedDevicePixelRatio && $.bracketedDevicePixelRatio() || 1,\n\tBUCKETS = {\n\t\toff: 'off',\n\t\ton: 'on',\n\t\tcontrol: 'control'\n\t};\n\nexport { BUCKETS };\n\nexport default {\n\tTHUMBNAIL_SIZE: 320 * pixelRatio,\n\tEXTRACT_LENGTH: 525\n};\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/constants.js\n// module id = ./src/constants.js\n// module chunks = 0","/**\n * @module counts\n */\n\n/**\n * Gets the count bucket for the number of edits a user has made.\n *\n * The buckets are defined as part of\n * [the Popups schema](https://meta.wikimedia.org/wiki/Schema:Popups).\n *\n * Extracted from `mw.popups.schemaPopups.getEditCountBucket`.\n *\n * @param {Number} count\n * @return {String}\n */\nexports.getEditCountBucket = function getEditCountBucket( count ) {\n\tvar bucket;\n\n\tif ( count === 0 ) {\n\t\tbucket = '0';\n\t} else if ( count >= 1 && count <= 4 ) {\n\t\tbucket = '1-4';\n\t} else if ( count >= 5 && count <= 99 ) {\n\t\tbucket = '5-99';\n\t} else if ( count >= 100 && count <= 999 ) {\n\t\tbucket = '100-999';\n\t} else if ( count >= 1000 ) {\n\t\tbucket = '1000+';\n\t}\n\n\treturn bucket + ' edits';\n};\n\n/**\n * Gets the count bucket for the number of previews a user has seen.\n *\n * If local storage isn't available - because the user has disabled it\n * or the browser doesn't support it - then then \"unknown\" is returned.\n *\n * The buckets are defined as part of\n * [the Popups schema](https://meta.wikimedia.org/wiki/Schema:Popups).\n *\n * Extracted from `mw.popups.getPreviewCountBucket`.\n *\n * @param {Number} count\n * @return {String}\n */\nexports.getPreviewCountBucket = function getPreviewCountBucket( count ) {\n\tvar bucket;\n\n\tif ( count === 0 ) {\n\t\tbucket = '0';\n\t} else if ( count >= 1 && count <= 4 ) {\n\t\tbucket = '1-4';\n\t} else if ( count >= 5 && count <= 20 ) {\n\t\tbucket = '5-20';\n\t} else if ( count >= 21 ) {\n\t\tbucket = '21+';\n\t}\n\n\treturn bucket !== undefined ? ( bucket + ' previews' ) : 'unknown';\n};\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/counts.js\n// module id = ./src/counts.js\n// module chunks = 0","/**\n * @module experiments\n */\n\n/**\n * @interface Experiments\n *\n * @global\n */\n\n/**\n * Creates a helper wrapper for the MediaWiki-provided\n * `mw.experiments#getBucket` bucketing function.\n *\n * @param {mw.experiments} mwExperiments The `mw.experiments` singleton instance\n * @return {Experiments}\n */\nexport default function createExperiments( mwExperiments ) {\n\treturn {\n\n\t\t/**\n\t\t * Gets whether something is true given a name and a token.\n\t\t *\n\t\t * @example\n\t\t * import createExperiments from './src/experiments';\n\t\t * const experiments = createExperiments( mw.experiments );\n\t\t * const isFooEnabled = experiments.weightedBoolean(\n\t\t * 'foo',\n\t\t * 10 / 100, // 10% of all unique tokens should have foo enabled.\n\t\t * token\n\t\t * );\n\t\t *\n\t\t * @function\n\t\t * @name Experiments#weightedBoolean\n\t\t * @param {String} name The name of the thing. Since this is used as the\n\t\t * name of the underlying experiment it should be unique to reduce the\n\t\t * likelihood of collisions with other enabled experiments\n\t\t * @param {Number} trueWeight A number between 0 and 1, representing the\n\t\t * probability of the thing being true\n\t\t * @param {String} token A token associated with the user for the duration\n\t\t * of the experiment\n\t\t * @return {Boolean}\n\t\t */\n\t\tweightedBoolean: function ( name, trueWeight, token ) {\n\t\t\treturn mwExperiments.getBucket( {\n\t\t\t\tenabled: true,\n\n\t\t\t\tname: name,\n\t\t\t\tbuckets: {\n\t\t\t\t\t'true': trueWeight,\n\t\t\t\t\t'false': 1 - trueWeight\n\t\t\t\t}\n\t\t\t}, token ) === 'true';\n\t\t}\n\t};\n}\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/experiments.js\n// module id = ./src/experiments.js\n// module chunks = 0","var $ = jQuery,\n\tmw = window.mediaWiki;\n\n/**\n * Improves the plain text extracts\n * @param {String} plainTextExtract\n * @param {String} title\n * @returns {Array}\n */\nexport function formatPlainTextExtract( plainTextExtract, title ) {\n\tvar extract = plainTextExtract;\n\tif ( plainTextExtract === undefined ) {\n\t\treturn [];\n\t}\n\n\textract = removeParentheticals( extract );\n\textract = removeTrailingEllipsis( extract );\n\n\t// After cleaning the extract it may have been blanked\n\tif ( extract.length === 0 ) {\n\t\treturn [];\n\t}\n\n\textract = makeTitleInExtractBold( extract, title );\n\treturn extract;\n}\n\n/**\n * Converts the extract into a list of elements, which correspond to fragments\n * of the extract. Fragments that match the title verbatim are wrapped in a\n * `<b>` element.\n *\n * Using the bolded elements of the extract of the page directly is covered by\n * [T141651](https://phabricator.wikimedia.org/T141651).\n *\n * Extracted from `mw.popups.renderer.article.getProcessedElements`.\n *\n * @param {String} extract\n * @param {String} title\n * @return {Array} A set of HTML Elements\n */\nfunction makeTitleInExtractBold( extract, title ) {\n\tvar regExp, escapedTitle,\n\t\telements = [],\n\t\tboldIdentifier = '<bi-' + Math.random() + '>',\n\t\tsnip = '<snip-' + Math.random() + '>';\n\n\ttitle = title.replace( /\\s+/g, ' ' ).trim(); // Remove extra white spaces\n\tescapedTitle = mw.RegExp.escape( title ); // Escape RegExp elements\n\tregExp = new RegExp( '(^|\\\\s)(' + escapedTitle + ')(|$)', 'i' );\n\n\t// Remove text in parentheses along with the parentheses\n\textract = extract.replace( /\\s+/, ' ' ); // Remove extra white spaces\n\n\t// Make title bold in the extract text\n\t// As the extract is html escaped there can be no such string in it\n\t// Also, the title is escaped of RegExp elements thus can't have \"*\"\n\textract = extract.replace( regExp, '$1' + snip + boldIdentifier + '$2' + snip + '$3' );\n\textract = extract.split( snip );\n\n\t$.each( extract, function ( index, part ) {\n\t\tif ( part.indexOf( boldIdentifier ) === 0 ) {\n\t\t\telements.push( $( '<b>' ).text( part.substring( boldIdentifier.length ) ) );\n\t\t} else {\n\t\t\telements.push( document.createTextNode( part ) );\n\t\t}\n\t} );\n\n\treturn elements;\n}\n\n/**\n * Removes the trailing ellipsis from the extract, if it's there.\n *\n * This function was extracted from\n * `mw.popups.renderer.article#removeEllipsis`.\n *\n * @param {String} extract\n * @return {String}\n */\nexport function removeTrailingEllipsis( extract ) {\n\treturn extract.replace( /\\.\\.\\.$/, '' );\n}\n\n/**\n * Removes parentheticals from the extract.\n *\n * If the parenthesis are unbalanced or out of order, then the extract is\n * returned without further processing.\n *\n * This function was extracted from\n * `mw.popups.renderer.article#removeParensFromText`.\n *\n * @param {String} extract\n * @return {String}\n */\nexport function removeParentheticals( extract ) {\n\tvar\n\t\tch,\n\t\tresult = '',\n\t\tlevel = 0,\n\t\ti = 0;\n\n\tfor ( i; i < extract.length; i++ ) {\n\t\tch = extract.charAt( i );\n\n\t\tif ( ch === ')' && level === 0 ) {\n\t\t\treturn extract;\n\t\t}\n\t\tif ( ch === '(' ) {\n\t\t\tlevel++;\n\t\t\tcontinue;\n\t\t} else if ( ch === ')' ) {\n\t\t\tlevel--;\n\t\t\tcontinue;\n\t\t}\n\t\tif ( level === 0 ) {\n\t\t\t// Remove leading spaces before brackets\n\t\t\tif ( ch === ' ' && extract.charAt( i + 1 ) === '(' ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tresult += ch;\n\t\t}\n\t}\n\n\treturn ( level === 0 ) ? result : extract;\n}\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/formatter.js\n// module id = ./src/formatter.js\n// module chunks = 0","import constants from '../constants';\nimport createMediaWikiApiGateway from './mediawiki';\nimport createRESTBaseGateway from './rest';\nimport * as formatters from './restFormatters';\n\nvar mw = mediaWiki,\n\t$ = jQuery;\n\n// Note that this interface definition is in the global scope.\n/**\n * The interface implemented by all preview gateways.\n *\n * @interface Gateway\n */\n\n/**\n * Fetches a preview for a page.\n *\n * If the underlying request is successful and contains data about the page,\n * then the resulting promise will resolve. If not, then it will reject.\n *\n * @function\n * @name Gateway#getPageSummary\n * @param {String} title The title of the page\n * @returns {jQuery.Promise<PreviewModel>}\n */\n\n/**\n * Creates a gateway with sensible values for the dependencies.\n *\n * @param {mw.Map} config\n * @return {Gateway}\n */\nexport default function createGateway( config ) {\n\tswitch ( config.get( 'wgPopupsGateway' ) ) {\n\t\tcase 'mwApiPlain':\n\t\t\treturn createMediaWikiApiGateway( new mw.Api(), constants );\n\t\tcase 'restbasePlain':\n\t\t\treturn createRESTBaseGateway( $.ajax, constants, formatters.parsePlainTextResponse );\n\t\tcase 'restbaseHTML':\n\t\t\treturn createRESTBaseGateway( $.ajax, constants, formatters.parseHTMLResponse );\n\t\tdefault:\n\t\t\tthrow new Error( 'Unknown gateway' );\n\t}\n}\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/gateway/index.js\n// module id = ./src/gateway/index.js\n// module chunks = 0","/**\n * @module gateway/mediawiki\n */\n\n/**\n * @interface MediaWikiGateway\n * @extends Gateway\n *\n * @global\n */\n\nimport { createModel } from '../preview/model';\nimport * as formatter from '../formatter';\n\n// Public and private cache lifetime (5 minutes)\n//\n// FIXME: Move this to src/constants.js.\nvar CACHE_LIFETIME = 300,\n\t$ = jQuery;\n\n/**\n * Creates an instance of the MediaWiki API gateway.\n *\n * @param {mw.Api} api\n * @param {Object} config Configuration that affects the major behavior of the\n * gateway.\n * @param {Number} config.THUMBNAIL_SIZE The length of the major dimension of\n * the thumbnail.\n * @param {Number} config.EXTRACT_LENGTH The maximum length, in characters,\n * of the extract.\n * @returns {MediaWikiGateway}\n */\nexport default function createMediaWikiApiGateway( api, config ) {\n\n\t/**\n\t * Fetches page data from the API.\n\t *\n\t * @function\n\t * @name MediaWikiGateway#fetch\n\t * @param {String} title\n\t * @return {jQuery.Promise}\n\t */\n\tfunction fetch( title ) {\n\t\treturn api.get( {\n\t\t\taction: 'query',\n\t\t\tprop: 'info|extracts|pageimages|revisions|info',\n\t\t\tformatversion: 2,\n\t\t\tredirects: true,\n\t\t\texintro: true,\n\t\t\texchars: config.EXTRACT_LENGTH,\n\n\t\t\t// There is an added geometric limit on .mwe-popups-extract\n\t\t\t// so that text does not overflow from the card.\n\t\t\texplaintext: true,\n\n\t\t\tpiprop: 'thumbnail',\n\t\t\tpithumbsize: config.THUMBNAIL_SIZE,\n\t\t\tpilicense: 'any',\n\t\t\trvprop: 'timestamp',\n\t\t\tinprop: 'url',\n\t\t\ttitles: title,\n\t\t\tsmaxage: CACHE_LIFETIME,\n\t\t\tmaxage: CACHE_LIFETIME,\n\t\t\tuselang: 'content'\n\t\t}, {\n\t\t\theaders: {\n\t\t\t\t'X-Analytics': 'preview=1'\n\t\t\t}\n\t\t} );\n\t}\n\n\tfunction getPageSummary( title ) {\n\t\treturn fetch( title )\n\t\t\t.then( extractPageFromResponse )\n\t\t\t.then( formatPlainTextExtract )\n\t\t\t.then( convertPageToModel );\n\t}\n\n\treturn {\n\t\tfetch: fetch,\n\t\textractPageFromResponse: extractPageFromResponse,\n\t\tconvertPageToModel: convertPageToModel,\n\t\tgetPageSummary: getPageSummary,\n\t\tformatPlainTextExtract: formatPlainTextExtract\n\t};\n}\n\n/**\n * Extracts page data from the API response.\n *\n * @function\n * @name MediaWikiGateway#extractPageFromResponse\n * @param {Object} data The response\n * @throws {Error} If the response is empty or doesn't contain data about the\n * page\n * @returns {Object}\n */\nfunction extractPageFromResponse( data ) {\n\tif (\n\t\tdata.query &&\n\t\tdata.query.pages &&\n\t\tdata.query.pages.length\n\t) {\n\t\treturn data.query.pages[ 0 ];\n\t}\n\n\tthrow new Error( 'API response `query.pages` is empty.' );\n}\n\n/**\n * Make plain text nicer by applying formatter.\n *\n * @function\n * @name MediaWikiGateway#formatPlainTextExtract\n * @param {Object} data The response\n * @returns {Object}\n */\nfunction formatPlainTextExtract( data ) {\n\tvar result = $.extend( {}, data );\n\tresult.extract = formatter.formatPlainTextExtract( data.extract, data.title );\n\treturn result;\n}\n\n/**\n * Converts the API response to a preview model.\n *\n * @function\n * @name MediaWikiGateway#convertPageToModel\n * @param {Object} page\n * @returns {PreviewModel}\n */\nfunction convertPageToModel( page ) {\n\treturn createModel(\n\t\tpage.title,\n\t\tpage.canonicalurl,\n\t\tpage.pagelanguagehtmlcode,\n\t\tpage.pagelanguagedir,\n\t\tpage.extract,\n\t\tpage.thumbnail\n\t);\n}\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/gateway/mediawiki.js\n// module id = ./src/gateway/mediawiki.js\n// module chunks = 0","/**\n * @module gateway/rest\n */\n\nimport { createModel, createNullModel } from '../preview/model';\n\nvar RESTBASE_ENDPOINT = '/api/rest_v1/page/summary/',\n\tRESTBASE_PROFILE = 'https://www.mediawiki.org/wiki/Specs/Summary/1.2.0',\n\tmw = window.mediaWiki,\n\t$ = jQuery;\n/**\n * @interface RESTBaseGateway\n * @extends Gateway\n *\n * @global\n */\n\n/**\n * Creates an instance of the RESTBase gateway.\n *\n * This gateway differs from the {@link MediaWikiGateway MediaWiki gateway} in\n * that it fetches page data from [the RESTBase page summary endpoint][0].\n *\n * [0]: https://en.wikipedia.org/api/rest_v1/#!/Page_content/get_page_summary_title\n *\n * @param {Function} ajax A function with the same signature as `jQuery.ajax`\n * @param {Object} config Configuration that affects the major behavior of the\n * gateway.\n * @param {Number} config.THUMBNAIL_SIZE The length of the major dimension of\n * the thumbnail.\n * @param {Function} extractParser A function that takes response and returns parsed extract\n * @returns {RESTBaseGateway}\n */\nexport default function createRESTBaseGateway( ajax, config, extractParser ) {\n\n\t/**\n\t * Fetches page data from [the RESTBase page summary endpoint][0].\n\t *\n\t * [0]: https://en.wikipedia.org/api/rest_v1/#!/Page_content/get_page_summary_title\n\t *\n\t * @function\n\t * @name MediaWikiGateway#fetch\n\t * @param {String} title\n\t * @return {jQuery.Promise}\n\t */\n\tfunction fetch( title ) {\n\t\treturn ajax( {\n\t\t\turl: RESTBASE_ENDPOINT + encodeURIComponent( title ),\n\t\t\theaders: {\n\t\t\t\tAccept: 'application/json; charset=utf-8; ' +\n\t\t\t\t\t'profile=\"' + RESTBASE_PROFILE + '\"'\n\t\t\t}\n\t\t} );\n\t}\n\n\tfunction getPageSummary( title ) {\n\t\tvar result = $.Deferred();\n\n\t\tfetch( title )\n\t\t\t.then(\n\t\t\t\tfunction ( page ) {\n\t\t\t\t\tresult.resolve(\n\t\t\t\t\t\tconvertPageToModel( page, config.THUMBNAIL_SIZE, extractParser ) );\n\t\t\t\t},\n\t\t\t\tfunction ( jqXHR ) {\n\t\t\t\t\tif ( jqXHR.status === 404 ) {\n\n\t\t\t\t\t\tresult.resolve(\n\t\t\t\t\t\t\tcreateNullModel( title )\n\t\t\t\t\t\t);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresult.reject();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t);\n\n\t\treturn result.promise();\n\t}\n\n\treturn {\n\t\tfetch: fetch,\n\t\tconvertPageToModel: convertPageToModel,\n\t\tgetPageSummary: getPageSummary\n\t};\n}\n\n/**\n * Resizes the thumbnail to the requested width, preserving its aspect ratio.\n *\n * The requested width is limited to that of the original image unless the image\n * is an SVG, which can be scaled infinitely.\n *\n * This function is only intended to mangle the pretty thumbnail URLs used on\n * Wikimedia Commons. Once [an official thumb API](https://phabricator.wikimedia.org/T66214)\n * is fully specified and implemented, this function can be made more general.\n *\n * @param {Object} thumbnail The thumbnail image\n * @param {Object} original The original image\n * @param {Number} thumbSize The requested size\n * @returns {Object}\n */\nfunction generateThumbnailData( thumbnail, original, thumbSize ) {\n\tvar parts = thumbnail.source.split( '/' ),\n\t\tlastPart = parts[ parts.length - 1 ],\n\t\tfilename,\n\t\twidth,\n\t\theight;\n\n\t// The last part, the thumbnail's full filename, is in the following form:\n\t// ${width}px-${filename}.${extension}. Splitting the thumbnail's filename\n\t// makes this function resilient to the thumbnail not having the same\n\t// extension as the original image, which is definitely the case for SVG's\n\t// where the thumbnail's extension is .svg.png.\n\tfilename = lastPart.substr( lastPart.indexOf( 'px-' ) + 3 );\n\n\t// Scale the thumbnail's largest dimension.\n\tif ( thumbnail.width > thumbnail.height ) {\n\t\twidth = thumbSize;\n\t\theight = Math.floor( ( thumbSize / thumbnail.width ) * thumbnail.height );\n\t} else {\n\t\twidth = Math.floor( ( thumbSize / thumbnail.height ) * thumbnail.width );\n\t\theight = thumbSize;\n\t}\n\n\t// If the image isn't an SVG, then it shouldn't be scaled past its original\n\t// dimensions.\n\tif ( width >= original.width && filename.indexOf( '.svg' ) === -1 ) {\n\t\treturn original;\n\t}\n\n\tparts[ parts.length - 1 ] = width + 'px-' + filename;\n\n\treturn {\n\t\tsource: parts.join( '/' ),\n\t\twidth: width,\n\t\theight: height\n\t};\n}\n\n/**\n * Converts the API response to a preview model.\n *\n * @function\n * @name RESTBaseGateway#convertPageToModel\n * @param {Object} page\n * @param {Number} thumbSize\n * @param {Function} extractParser\n * @returns {PreviewModel}\n */\nfunction convertPageToModel( page, thumbSize, extractParser ) {\n\treturn createModel(\n\t\tpage.title,\n\t\tnew mw.Title( page.title ).getUrl(),\n\t\tpage.lang,\n\t\tpage.dir,\n\t\textractParser( page ),\n\t\tpage.thumbnail ? generateThumbnailData( page.thumbnail, page.originalimage, thumbSize ) : undefined\n\t);\n}\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/gateway/rest.js\n// module id = ./src/gateway/rest.js\n// module chunks = 0","import * as formatter from '../formatter';\n\n/**\n * Prepare extract\n * @param {Object} page Rest response\n * @returns {Array} An array of DOM Elements\n */\nexport function parseHTMLResponse( page ) {\n\tvar extract = page.extract_html;\n\textract = formatter.removeTrailingEllipsis( extract );\n\textract = formatter.removeParentheticals( extract );\n\n\treturn extract.length === 0 ? [] : $.parseHTML( extract );\n}\n\n/**\n * Prepare extract\n * @param {Object} page Rest response\n * @returns {Array} An array of DOM Elements\n */\nexport function parsePlainTextResponse( page ) {\n\treturn formatter.formatPlainTextExtract( page.extract, page.title );\n}\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/gateway/restFormatters.js\n// module id = ./src/gateway/restFormatters.js\n// module chunks = 0","/**\n * What is the bucket for the given user given the enabled sampling rate?\n *\n * @param {mw.experiments} experiments The `mw.experiments` singleton instance\n * @param {Number} experimentGroupSize [0,1] of users of which should be subjected to an\n * A/B test. The remaining users will be put in the 'off' bucket.\n * @param {string} sessionId a unique session token\n *\n * @return {string} bucket that the user belongs to (off/control/on)\n */\nfunction getUserBucket( experiments, experimentGroupSize, sessionId ) {\n\tvar control = experimentGroupSize / 2;\n\tif ( !experimentGroupSize ) {\n\t\t// no users are subject to experiment\n\t\treturn 'on';\n\t}\n\n\treturn experiments.getBucket( {\n\t\tname: 'ext.Popups.visibility',\n\t\tenabled: true,\n\t\tbuckets: {\n\t\t\toff: 1 - experimentGroupSize,\n\t\t\tcontrol: control,\n\t\t\ton: control\n\t\t}\n\t}, sessionId );\n}\n\nexport default getUserBucket;\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/getUserBucket.js\n// module id = ./src/getUserBucket.js\n// module chunks = 0","/**\n * @module popups\n */\n\nimport * as Redux from 'redux';\nimport * as ReduxThunk from 'redux-thunk';\n\nimport createGateway from './gateway';\nimport createUserSettings from './userSettings';\nimport createPreviewBehavior from './previewBehavior';\nimport createSettingsDialogRenderer from './ui/settingsDialog';\nimport registerChangeListener from './changeListener';\nimport createIsEnabled from './isEnabled';\nimport { fromElement as titleFromElement } from './title';\nimport { init as rendererInit } from './ui/renderer';\nimport createExperiments from './experiments';\nimport { isEnabled as isStatsvEnabled } from './instrumentation/statsv';\nimport { isEnabled as isEventLoggingEnabled } from './instrumentation/eventLogging';\nimport changeListeners from './changeListeners';\nimport * as actions from './actions';\nimport reducers from './reducers';\nimport createMediaWikiPopupsObject from './integrations/mwpopups';\nimport getUserBucket from './getUserBucket';\n\nvar mw = mediaWiki,\n\t$ = jQuery,\n\n\tBLACKLISTED_LINKS = [\n\t\t'.extiw',\n\t\t'.image',\n\t\t'.new',\n\t\t'.internal',\n\t\t'.external',\n\t\t'.oo-ui-buttonedElement-button',\n\t\t'.cancelLink a'\n\t];\n\n/**\n * @typedef {Function} EventTracker\n *\n * An analytics event tracker, i.e. `mw.track`.\n *\n * @param {String} topic\n * @param {Object} data\n *\n * @global\n */\n\n/**\n * Gets the appropriate analytics event tracker for logging metrics to StatsD\n * via [the \"StatsD timers and counters\" analytics event protocol][0].\n *\n * If logging metrics to StatsD is enabled for the duration of the user's\n * session, then the appriopriate function is `mw.track`; otherwise it's\n * `$.noop`.\n *\n * [0]: https://github.com/wikimedia/mediawiki-extensions-WikimediaEvents/blob/29c864a0/modules/ext.wikimediaEvents.statsd.js\n *\n * @param {Object} user\n * @param {Object} config\n * @param {Experiments} experiments\n * @return {EventTracker}\n */\nfunction getStatsvTracker( user, config, experiments ) {\n\treturn isStatsvEnabled( user, config, experiments ) ? mw.track : $.noop;\n}\n\n/**\n * Gets the appropriate analytics event tracker for logging EventLogging events\n * via [the \"EventLogging subscriber\" analytics event protocol][0].\n *\n * If logging EventLogging events is enabled for the duration of the user's\n * session, then the appriopriate function is `mw.track`; otherwise it's\n * `$.noop`.\n *\n * [0]: https://github.com/wikimedia/mediawiki-extensions-EventLogging/blob/d1409759/modules/ext.eventLogging.subscriber.js\n *\n * @param {Object} user\n * @param {Object} config\n * @param {String} bucket for user\n * @param {Window} window\n * @return {EventTracker}\n */\nfunction getEventLoggingTracker( user, config, bucket, window ) {\n\treturn isEventLoggingEnabled(\n\t\tuser,\n\t\tconfig,\n\t\tbucket,\n\t\twindow\n\t) ? mw.track : $.noop;\n}\n\n/**\n * Subscribes the registered change listeners to the\n * [store](http://redux.js.org/docs/api/Store.html#store).\n *\n * @param {Redux.Store} store\n * @param {Object} actions\n * @param {UserSettings} userSettings\n * @param {Function} settingsDialog\n * @param {PreviewBehavior} previewBehavior\n * @param {EventTracker} statsvTracker\n * @param {EventTracker} eventLoggingTracker\n */\nfunction registerChangeListeners( store, actions, userSettings, settingsDialog, previewBehavior, statsvTracker, eventLoggingTracker ) {\n\tregisterChangeListener( store, changeListeners.footerLink( actions ) );\n\tregisterChangeListener( store, changeListeners.linkTitle() );\n\tregisterChangeListener( store, changeListeners.render( previewBehavior ) );\n\tregisterChangeListener( store, changeListeners.statsv( actions, statsvTracker ) );\n\tregisterChangeListener( store, changeListeners.syncUserSettings( userSettings ) );\n\tregisterChangeListener( store, changeListeners.settings( actions, settingsDialog ) );\n\tregisterChangeListener( store, changeListeners.eventLogging( actions, eventLoggingTracker ) );\n}\n\n/*\n * Initialize the application by:\n * 1. Creating the state store\n * 2. Binding the actions to such store\n * 3. Trigger the boot action to bootstrap the system\n * 4. When the page content is ready:\n * - Process the eligible links for page previews\n * - Initialize the renderer\n * - Bind hover and click events to the eligible links to trigger actions\n */\nmw.requestIdleCallback( function () {\n\tvar compose = Redux.compose,\n\t\tuserBucket,\n\t\tstore,\n\t\tboundActions,\n\n\t\t// So-called \"services\".\n\t\tgenerateToken = mw.user.generateRandomSessionId,\n\t\tgateway = createGateway( mw.config ),\n\t\tuserSettings,\n\t\tsettingsDialog,\n\t\texperiments,\n\t\tstatsvTracker,\n\t\teventLoggingTracker,\n\t\tisEnabled,\n\t\tpreviewBehavior;\n\n\tuserBucket = getUserBucket( mw.experiments, mw.config.get( 'wgPopupsAnonsExperimentalGroupSize' ),\n\t\tmw.user.sessionId() );\n\tuserSettings = createUserSettings( mw.storage );\n\tsettingsDialog = createSettingsDialogRenderer();\n\texperiments = createExperiments( mw.experiments );\n\tstatsvTracker = getStatsvTracker( mw.user, mw.config, experiments );\n\teventLoggingTracker = getEventLoggingTracker(\n\t\tmw.user,\n\t\tmw.config,\n\t\tuserBucket,\n\t\twindow\n\t);\n\n\tisEnabled = createIsEnabled( mw.user, userSettings, mw.config, userBucket );\n\n\t// If debug mode is enabled, then enable Redux DevTools.\n\tif ( mw.config.get( 'debug' ) === true ) {\n\t\t// eslint-disable-next-line no-underscore-dangle\n\t\tcompose = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;\n\t}\n\n\tstore = Redux.createStore(\n\t\tRedux.combineReducers( reducers ),\n\t\tcompose( Redux.applyMiddleware(\n\t\t\tReduxThunk.default\n\t\t) )\n\t);\n\tboundActions = Redux.bindActionCreators( actions, store.dispatch );\n\n\tpreviewBehavior = createPreviewBehavior( mw.config, mw.user, boundActions );\n\n\tregisterChangeListeners(\n\t\tstore, boundActions, userSettings, settingsDialog,\n\t\tpreviewBehavior, statsvTracker, eventLoggingTracker\n\t);\n\n\tboundActions.boot(\n\t\tisEnabled,\n\t\tmw.user,\n\t\tuserSettings,\n\t\tgenerateToken,\n\t\tmw.config\n\t);\n\n\t/*\n\t * Register external interface exposing popups internals so that other\n\t * extensions can query it (T171287)\n\t */\n\tmw.popups = createMediaWikiPopupsObject( store );\n\n\tmw.hook( 'wikipage.content' ).add( function ( $container ) {\n\t\tvar invalidLinksSelector = BLACKLISTED_LINKS.join( ', ' ),\n\t\t\tvalidLinkSelector = 'a[href][title]:not(' + invalidLinksSelector + ')';\n\n\t\trendererInit();\n\n\t\t$container\n\t\t\t.on( 'mouseover keyup', validLinkSelector, function ( event ) {\n\t\t\t\tvar mwTitle = titleFromElement( this, mw.config );\n\n\t\t\t\tif ( mwTitle ) {\n\t\t\t\t\tboundActions.linkDwell( mwTitle, this, event, gateway, generateToken );\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.on( 'mouseout blur', validLinkSelector, function () {\n\t\t\t\tvar mwTitle = titleFromElement( this, mw.config );\n\n\t\t\t\tif ( mwTitle ) {\n\t\t\t\t\tboundActions.abandon( this );\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.on( 'click', validLinkSelector, function () {\n\t\t\t\tvar mwTitle = titleFromElement( this, mw.config );\n\n\t\t\t\tif ( mwTitle ) {\n\t\t\t\t\tboundActions.linkClick( this );\n\t\t\t\t}\n\t\t\t} );\n\n\t} );\n} );\n\nwindow.Redux = Redux;\nwindow.ReduxThunk = ReduxThunk;\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/index.js\n// module id = ./src/index.js\n// module chunks = 0","/**\n * @module instrumentation/eventLogging\n */\nimport { BUCKETS } from './../constants';\n\n/**\n * Gets whether EventLogging logging is enabled for the duration of the user's\n * session.\n * If wgPopupsEventLogging is false this will return false unless debug=true has\n * been enabled.\n * If an experiment is being run (ie. wgPopupsAnonsExperimentalGroupSize has been\n * defined) then event logging will only be enabled for those in the `on` or `control`\n * groups.\n * However, if the UA doesn't support [the Beacon API][1], then bucketing is\n * disabled.\n *\n * [1]: https://w3c.github.io/beacon/\n *\n * @param {mw.user} user The `mw.user` singleton instance\n * @param {mw.Map} config The `mw.config` singleton instance\n * @param {String} bucket that the user is in (see constants.js)\n * @param {Window} window\n * @return {Boolean}\n */\nexport function isEnabled( user, config, bucket, window ) {\n\t// if debug mode is on, always enable event logging. @see T168847\n\tif ( config.get( 'debug' ) === true ) {\n\t\treturn true;\n\t}\n\n\tif ( !config.get( 'wgPopupsEventLogging' ) ) {\n\t\treturn false;\n\t}\n\n\tif (\n\t\t!window.navigator ||\n\t\t!$.isFunction( window.navigator.sendBeacon )\n\t) {\n\t\treturn false;\n\t}\n\n\treturn user.isAnon() && bucket !== BUCKETS.off;\n}\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/instrumentation/eventLogging.js\n// module id = ./src/instrumentation/eventLogging.js\n// module chunks = 0","/**\n * @module instrumentation/statsv\n */\n\n/**\n * Gets whether Graphite logging (via [the statsv HTTP endpoint][0]) is enabled\n * for the duration of the user's session. The bucketing rate is controlled by\n * `wgPopupsStatsvSamplingRate`.\n *\n * [0]: https://wikitech.wikimedia.org/wiki/Graphite#statsv\n *\n * @param {mw.user} user The `mw.user` singleton instance\n * @param {mw.Map} config The `mw.config` singleton instance\n * @param {Experiments} experiments\n * @returns {Boolean}\n */\nexport function isEnabled( user, config, experiments ) {\n\tvar bucketingRate = config.get( 'wgPopupsStatsvSamplingRate', 0 );\n\n\treturn experiments.weightedBoolean(\n\t\t'ext.Popups.statsv',\n\t\tbucketingRate,\n\t\tuser.sessionId()\n\t);\n}\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/instrumentation/statsv.js\n// module id = ./src/instrumentation/statsv.js\n// module chunks = 0","/**\n * @module MediaWiki-Popups Integration\n */\n\n/**\n * This function provides a mw.popups object which can be used by 3rd party\n * to interact with Popups. Currently it allows only to read isEnabled flag.\n *\n * @param {Redux.Store} store Popups store\n * @return {Object} external Popups interface\n */\nexport default function createMwPopups( store ) {\n\treturn {\n\t\tisEnabled: function isEnabled() {\n\t\t\treturn store.getState().preview.enabled;\n\t\t}\n\t};\n\n}\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/integrations/mwpopups.js\n// module id = ./src/integrations/mwpopups.js\n// module chunks = 0","/**\n * @module isEnabled\n */\nimport { BUCKETS } from './constants';\n\n/**\n * Given the global state of the application, creates a function that gets\n * whether or not the user should have Page Previews enabled.\n *\n * Page Previews is disabled when the Navigation Popups gadget is enabled.\n *\n * If Page Previews is configured as a beta feature (see\n * `$wgPopupsBetaFeature`), the user must be logged in and have enabled the\n * beta feature in order to see previews. Logged out users won't be able\n * to see the feature.\n *\n * If Page Previews is configured as a user preference, then the user must\n * either be logged in and have enabled the preference or be logged out and have\n * not disabled previews via the settings modal. Logged out users who have not\n * disabled or enabled the previews via the settings modal will be subject to\n * wgPopupsAnonsExperimentalGroupSize if defined.\n *\n * @param {mw.user} user The `mw.user` singleton instance\n * @param {Object} userSettings An object returned by `userSettings.js`\n * @param {mw.Map} config\n * @param {String} bucket the user belongs to (off, on or control)\n *\n * @return {Boolean}\n */\nexport default function isEnabled( user, userSettings, config, bucket ) {\n\tif ( config.get( 'wgPopupsConflictsWithNavPopupGadget' ) ) {\n\t\treturn false;\n\t}\n\n\tif ( !user.isAnon() ) {\n\t\treturn config.get( 'wgPopupsShouldSendModuleToUser' );\n\t}\n\n\tif ( config.get( 'wgPopupsBetaFeature' ) ) {\n\t\treturn false;\n\t}\n\n\tif ( !userSettings.hasIsEnabled() ) {\n\t\treturn bucket === BUCKETS.on;\n\t}\n\n\treturn userSettings.getIsEnabled();\n}\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/isEnabled.js\n// module id = ./src/isEnabled.js\n// module chunks = 0","/**\n * @module preview/model\n */\n\n/**\n * @constant {String}\n */\nexport var TYPE_GENERIC = 'generic';\n\n/**\n * @constant {String}\n */\nexport var TYPE_PAGE = 'page'; // eslint-disable-line one-var\n\n/**\n * @typedef {Object} PreviewModel\n * @property {String} title\n * @property {String} url The canonical URL of the page being previewed\n * @property {String} languageCode\n * @property {String} languageDirection Either \"ltr\" or \"rtl\"\n * @property {?Array} extract `undefined` if the extract isn't\n * viable, e.g. if it's empty after having ellipsis and parentheticals\n * removed\n * @property {String} type Either \"extract\" or \"generic\"\n * @property {?Object} thumbnail\n *\n * @global\n */\n\n/**\n * Creates a preview model.\n *\n * @param {String} title\n * @param {String} url The canonical URL of the page being previewed\n * @param {String} languageCode\n * @param {String} languageDirection Either \"ltr\" or \"rtl\"\n * @param {?Array} extract\n * @param {?Object} thumbnail\n * @return {PreviewModel}\n */\nexport function createModel(\n\ttitle,\n\turl,\n\tlanguageCode,\n\tlanguageDirection,\n\textract,\n\tthumbnail\n) {\n\tvar processedExtract = processExtract( extract );\n\n\treturn {\n\t\ttitle: title,\n\t\turl: url,\n\t\tlanguageCode: languageCode,\n\t\tlanguageDirection: languageDirection,\n\t\textract: processedExtract,\n\t\ttype: processedExtract === undefined ? TYPE_GENERIC : TYPE_PAGE,\n\t\tthumbnail: thumbnail\n\t};\n}\n\n/**\n * Creates an empty preview model.\n *\n * @param {String} title\n * @return {PreviewModel}\n */\nexport function createNullModel( title ) {\n\treturn createModel( title, '', '', '', [], '' );\n}\n\n/**\n * Processes the extract returned by the TextExtracts MediaWiki API query\n * module.\n *\n * If the extract is `undefined`, `null`, or empty, then `undefined` is\n * returned.\n *\n * @param {Array|undefined|null} extract\n * @return {Array|undefined} Array when extract is an not empty array, undefined otherwise\n */\nfunction processExtract( extract ) {\n\tif ( extract === undefined || extract === null || extract.length === 0 ) {\n\t\treturn undefined;\n\t}\n\treturn extract;\n}\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/preview/model.js\n// module id = ./src/preview/model.js\n// module chunks = 0","/**\n * @module previewBehaviour\n */\n\nvar mw = window.mediaWiki,\n\t$ = jQuery;\n\n/**\n * A collection of event handlers specific to how the user interacts with all\n * previews. The event handlers are are agnostic to how/when they are bound\n * //but not to what they are bound//, i.e. the showSettings event handler is\n * written to be bound to either an `<a>` or `<button>` element.\n *\n * @typedef {Object} ext.popups.PreviewBehavior\n * @property {String} settingsUrl\n * @property {Function} showSettings\n * @property {Function} previewDwell\n * @property {Function} previewAbandon\n * @property {Function} click handler for the entire preview\n */\n\n/**\n * Creates an instance of `ext.popups.PreviewBehavior`.\n *\n * If the user is logged out, then clicking the cog should show the settings\n * modal.\n *\n * If the user is logged in, then clicking the cog should send them to the\n * Special:Preferences page with the \"Beta features\" tab open if Page Previews\n * is enabled as a beta feature, or the \"Appearance\" tab otherwise.\n *\n * @param {mw.Map} config\n * @param {mw.User} user\n * @param {Object} actions The action creators bound to the Redux store\n * @return {ext.popups.PreviewBehavior}\n */\nexport default function createPreviewBehavior( config, user, actions ) {\n\tvar isBetaFeature = config.get( 'wgPopupsBetaFeature' ),\n\t\trawTitle,\n\t\tsettingsUrl,\n\t\tshowSettings = $.noop;\n\n\tif ( user.isAnon() ) {\n\t\tshowSettings = function ( event ) {\n\t\t\tevent.preventDefault();\n\n\t\t\tactions.showSettings();\n\t\t};\n\t} else {\n\t\trawTitle = 'Special:Preferences#mw-prefsection-';\n\t\trawTitle += isBetaFeature ? 'betafeatures' : 'rendering';\n\n\t\tsettingsUrl = mw.Title.newFromText( rawTitle )\n\t\t\t.getUrl();\n\t}\n\n\treturn {\n\t\tsettingsUrl: settingsUrl,\n\t\tshowSettings: showSettings,\n\t\tpreviewDwell: actions.previewDwell,\n\t\tpreviewAbandon: actions.abandon,\n\t\tpreviewShow: actions.previewShow,\n\t\tclick: actions.linkClick\n\t};\n}\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/previewBehavior.js\n// module id = ./src/previewBehavior.js\n// module chunks = 0","/**\n * @module reducers/eventLogging\n */\n\nimport actionTypes from '../actionTypes';\nimport nextState from './nextState';\nimport * as counts from '../counts';\n\n/**\n * Initialize the data that's shared between all events.\n *\n * @param {Object} bootAction\n * @return {Object}\n */\nfunction getBaseData( bootAction ) {\n\tvar result = {\n\t\tpageTitleSource: bootAction.page.title,\n\t\tnamespaceIdSource: bootAction.page.namespaceID,\n\t\tpageIdSource: bootAction.page.id,\n\t\tisAnon: bootAction.user.isAnon,\n\t\tpopupEnabled: bootAction.isEnabled,\n\t\tpageToken: bootAction.pageToken,\n\t\tsessionToken: bootAction.sessionToken,\n\t\tpreviewCountBucket: counts.getPreviewCountBucket( bootAction.user.previewCount ),\n\t\thovercardsSuppressedByGadget: bootAction.isNavPopupsEnabled\n\t};\n\n\tif ( !bootAction.user.isAnon ) {\n\t\tresult.editCountBucket = counts.getEditCountBucket( bootAction.user.editCount );\n\t}\n\n\treturn result;\n}\n\n/**\n * Takes data specific to the action and adds the following properties:\n *\n * * `linkInteractionToken`;\n * * `pageTitleHover` and `namespaceIdHover`; and\n * * `previewType` and `perceivedWait`, if a preview has been shown.\n *\n * @param {Object} interaction\n * @param {Object} actionData Data specific to the action, e.g. see\n * {@link module:reducers/eventLogging~createClosingEvent `createClosingEvent`}\n * @return {Object}\n */\nfunction createEvent( interaction, actionData ) {\n\tactionData.linkInteractionToken = interaction.token;\n\tactionData.pageTitleHover = interaction.title;\n\tactionData.namespaceIdHover = interaction.namespaceID;\n\n\t// Has the preview been shown?\n\tif ( interaction.timeToPreviewShow !== undefined ) {\n\t\tactionData.previewType = interaction.previewType;\n\t\tactionData.perceivedWait = interaction.timeToPreviewShow;\n\t}\n\n\treturn actionData;\n}\n\n/**\n * Creates an event that, when mixed into the base data (see\n * {@link module:reducers/eventLogging~getBaseData `getBaseData`}), represents\n * the user abandoning a link or preview.\n *\n * Since the event should be logged when the user has either abandoned a link or\n * dwelled on a different link, we refer to these events as \"closing\" events as\n * the link interaction has finished and a new one will be created later.\n *\n * If the link interaction is finalized, then no closing event is created.\n *\n * @param {Object} interaction\n * @return {Object|undefined}\n */\nfunction createClosingEvent( interaction ) {\n\tvar actionData = {\n\t\ttotalInteractionTime: Math.round( interaction.finished - interaction.started )\n\t};\n\n\tif ( interaction.finalized ) {\n\t\treturn undefined;\n\t}\n\n\t// Has the preview been shown? If so, then, in the context of the\n\t// instrumentation, then the preview has been dismissed by the user\n\t// rather than the user has abandoned the link.\n\tactionData.action = interaction.timeToPreviewShow ? 'dismissed' : 'dwelledButAbandoned';\n\n\treturn createEvent( interaction, actionData );\n}\n\n/**\n * Reducer for actions that may result in an event being logged with [the\n * Popups schema][0] via EventLogging.\n *\n * The complexity of this reducer reflects the complexity of [the schema][0],\n * which is compounded by the introduction of two delays introduced by the\n * system to provide reasonable performance and a consistent UX.\n *\n * The reducer must:\n *\n * * Accumulate the state required to log events. This state is\n * referred to as \"the interaction state\" or \"the interaction\";\n * * Enforce the invariant that one event is logged per interaction;\n * * Defend against delayed actions being dispatched; and, as a direct\n * consequence\n * * Handle transitioning from one interaction to another at the same time.\n *\n * Furthermore, we distinguish between \"finalizing\" and \"closing\" the current\n * interaction state. Since only one event should be logged per link\n * interaction, we say that the interaction state is *finalized* when an event\n * has been logged and is *closed* when a new interaction should be created.\n * In practice, the interaction state is only finalized when the user clicks a\n * link or a preview.\n *\n * [0]: https://meta.wikimedia.org/wiki/Schema:Popups\n *\n * @param {Object} state\n * @param {Object} action\n * @return {Object} The state resulting from reducing the action with the\n * current state\n */\nexport default function eventLogging( state, action ) {\n\tvar nextCount, newState,\n\t\tactionTypesWithTokens = [\n\t\t\tactionTypes.FETCH_COMPLETE,\n\t\t\tactionTypes.ABANDON_END,\n\t\t\tactionTypes.PREVIEW_SHOW\n\t\t];\n\n\tif ( state === undefined ) {\n\t\tstate = {\n\t\t\tpreviewCount: undefined,\n\t\t\tbaseData: {},\n\t\t\tinteraction: undefined,\n\t\t\tevent: undefined\n\t\t};\n\t}\n\n\t// Was the action delayed? Then it requires a token to be reduced. Enforce\n\t// this here to avoid repetion and reduce nesting below.\n\tif (\n\t\tactionTypesWithTokens.indexOf( action.type ) !== -1 &&\n\t\t( !state.interaction || action.token !== state.interaction.token )\n\t) {\n\t\treturn state;\n\t}\n\n\t// If there is no interaction ongoing, ignore all actions except for:\n\t// * Application initialization\n\t// * New link dwells (which start a new interaction)\n\t// * Clearing queued events\n\t//\n\t// For example, after ctrl+clicking a link or preview, any other actions\n\t// until the new interaction should be ignored.\n\tif (\n\t\t!state.interaction &&\n\t\taction.type !== actionTypes.BOOT &&\n\t\taction.type !== actionTypes.LINK_DWELL &&\n\t\taction.type !== actionTypes.EVENT_LOGGED &&\n\t\taction.type !== actionTypes.SETTINGS_CHANGE\n\t) {\n\t\treturn state;\n\t}\n\tswitch ( action.type ) {\n\t\tcase actionTypes.BOOT:\n\t\t\treturn nextState( state, {\n\t\t\t\tpreviewCount: action.user.previewCount,\n\t\t\t\tbaseData: getBaseData( action ),\n\t\t\t\tevent: {\n\t\t\t\t\taction: 'pageLoaded'\n\t\t\t\t}\n\t\t\t} );\n\n\t\tcase actionTypes.EVENT_LOGGED:\n\t\t\tnewState = nextState( state, {\n\t\t\t\tevent: undefined\n\t\t\t} );\n\n\t\t\t// If an event was logged with an interaction token, and it is still\n\t\t\t// the current interaction, finish the interaction since logging is\n\t\t\t// the exit point of the state machine and an interaction should never\n\t\t\t// be logged twice.\n\t\t\tif (\n\t\t\t\taction.event.linkInteractionToken &&\n\t\t\t\tstate.interaction &&\n\t\t\t\t( action.event.linkInteractionToken === state.interaction.token )\n\t\t\t) {\n\t\t\t\tnewState.interaction = undefined;\n\t\t\t}\n\t\t\treturn newState;\n\n\t\tcase actionTypes.FETCH_COMPLETE:\n\t\t\treturn nextState( state, {\n\t\t\t\tinteraction: nextState( state.interaction, {\n\t\t\t\t\tpreviewType: action.result.type\n\t\t\t\t} )\n\t\t\t} );\n\n\t\tcase actionTypes.PREVIEW_SHOW:\n\t\t\tnextCount = state.previewCount + 1;\n\n\t\t\treturn nextState( state, {\n\t\t\t\tpreviewCount: nextCount,\n\t\t\t\tbaseData: nextState( state.baseData, {\n\t\t\t\t\tpreviewCountBucket: counts.getPreviewCountBucket( nextCount )\n\t\t\t\t} ),\n\t\t\t\tinteraction: nextState( state.interaction, {\n\t\t\t\t\ttimeToPreviewShow: Math.round( action.timestamp - state.interaction.started )\n\t\t\t\t} )\n\t\t\t} );\n\n\t\tcase actionTypes.LINK_DWELL:\n\n\t\t\t// Not a new interaction?\n\t\t\tif ( state.interaction && action.el === state.interaction.link ) {\n\t\t\t\treturn nextState( state, {\n\t\t\t\t\tinteraction: nextState( state.interaction, {\n\t\t\t\t\t\tisUserDwelling: true\n\t\t\t\t\t} )\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\treturn nextState( state, {\n\n\t\t\t\t// TODO: Extract this object into a module that can be shared between\n\t\t\t\t// this and the preview reducer.\n\t\t\t\tinteraction: {\n\t\t\t\t\tlink: action.el,\n\t\t\t\t\ttitle: action.title,\n\t\t\t\t\tnamespaceID: action.namespaceID,\n\t\t\t\t\ttoken: action.token,\n\t\t\t\t\tstarted: action.timestamp,\n\n\t\t\t\t\tisUserDwelling: true\n\t\t\t\t},\n\n\t\t\t\t// Was the user interacting with another link? If so, then log the\n\t\t\t\t// abandoned event.\n\t\t\t\tevent: state.interaction ? createClosingEvent( state.interaction ) : undefined\n\t\t\t} );\n\n\t\tcase actionTypes.PREVIEW_DWELL:\n\t\t\treturn nextState( state, {\n\t\t\t\tinteraction: nextState( state.interaction, {\n\t\t\t\t\tisUserDwelling: true\n\t\t\t\t} )\n\t\t\t} );\n\n\t\tcase actionTypes.LINK_CLICK:\n\t\t\treturn nextState( state, {\n\t\t\t\tinteraction: nextState( state.interaction, {\n\t\t\t\t\tfinalized: true\n\t\t\t\t} ),\n\t\t\t\tevent: createEvent( state.interaction, {\n\t\t\t\t\taction: 'opened',\n\t\t\t\t\ttotalInteractionTime: Math.round( action.timestamp - state.interaction.started )\n\t\t\t\t} )\n\t\t\t} );\n\n\t\tcase actionTypes.ABANDON_START:\n\t\t\treturn nextState( state, {\n\t\t\t\tinteraction: nextState( state.interaction, {\n\t\t\t\t\tfinished: action.timestamp,\n\n\t\t\t\t\tisUserDwelling: false\n\t\t\t\t} )\n\t\t\t} );\n\n\t\tcase actionTypes.ABANDON_END:\n\t\t\tif ( !state.interaction.isUserDwelling ) {\n\t\t\t\treturn nextState( state, {\n\t\t\t\t\tinteraction: undefined,\n\t\t\t\t\tevent: createClosingEvent( state.interaction )\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\treturn state;\n\n\t\tcase actionTypes.SETTINGS_SHOW:\n\t\t\treturn nextState( state, {\n\t\t\t\tevent: createEvent( state.interaction, {\n\t\t\t\t\taction: 'tapped settings cog'\n\t\t\t\t} )\n\t\t\t} );\n\n\t\tcase actionTypes.SETTINGS_CHANGE:\n\t\t\tif ( action.wasEnabled && !action.enabled ) {\n\t\t\t\treturn nextState( state, {\n\t\t\t\t\tevent: {\n\t\t\t\t\t\taction: 'disabled',\n\t\t\t\t\t\tpopupEnabled: false\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t} else {\n\t\t\t\treturn state;\n\t\t\t}\n\t\tdefault:\n\t\t\treturn state;\n\t}\n}\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/reducers/eventLogging.js\n// module id = ./src/reducers/eventLogging.js\n// module chunks = 0","import eventLogging from './eventLogging';\nimport preview from './preview';\nimport settings from './settings';\nimport statsv from './statsv';\n\nexport default {\n\teventLogging: eventLogging,\n\tpreview: preview,\n\tsettings: settings,\n\tstatsv: statsv\n};\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/reducers/index.js\n// module id = ./src/reducers/index.js\n// module chunks = 0","/**\n * Creates the next state tree from the current state tree and some updates.\n *\n * N.B. OO.copy doesn't copy Element instances, whereas $.extend does.\n * However, OO.copy does copy properties whose values are undefined or null,\n * whereas $.extend doesn't. Since the state tree contains an Element instance\n * - the preview.activeLink property - and we want to copy undefined/null into\n * the state we need to manually iterate over updates and check with\n * hasOwnProperty to copy over to the new state.\n *\n * In [change listeners](/doc/change_listeners.md), for example, we talk about\n * the previous state and the current state (the `prevState` and `state`\n * parameters, respectively). Since\n * [reducers](http://redux.js.org/docs/basics/Reducers.html) take the current\n * state and an action and make updates, \"next state\" seems appropriate.\n *\n * @param {Object} state\n * @param {Object} updates\n * @return {Object}\n */\nexport default function nextState( state, updates ) {\n\tvar result = {},\n\t\tkey;\n\n\tfor ( key in state ) {\n\t\tif ( state.hasOwnProperty( key ) && !updates.hasOwnProperty( key ) ) {\n\t\t\tresult[ key ] = state[ key ];\n\t\t}\n\t}\n\n\tfor ( key in updates ) {\n\t\tif ( updates.hasOwnProperty( key ) ) {\n\t\t\tresult[ key ] = updates[ key ];\n\t\t}\n\t}\n\n\treturn result;\n}\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/reducers/nextState.js\n// module id = ./src/reducers/nextState.js\n// module chunks = 0","import actionTypes from '../actionTypes';\nimport nextState from './nextState';\n\n/**\n * Reducer for actions that modify the state of the preview model\n *\n * @param {Object} state before action\n * @param {Object} action Redux action that modified state.\n * Must have `type` property.\n * @return {Object} state after action\n */\nexport default function preview( state, action ) {\n\tif ( state === undefined ) {\n\t\tstate = {\n\t\t\tenabled: undefined,\n\t\t\tactiveLink: undefined,\n\t\t\tactiveEvent: undefined,\n\t\t\tactiveToken: '',\n\t\t\tshouldShow: false,\n\t\t\tisUserDwelling: false\n\t\t};\n\t}\n\n\tswitch ( action.type ) {\n\t\tcase actionTypes.BOOT:\n\t\t\treturn nextState( state, {\n\t\t\t\tenabled: action.isEnabled\n\t\t\t} );\n\t\tcase actionTypes.SETTINGS_CHANGE:\n\t\t\treturn nextState( state, {\n\t\t\t\tenabled: action.enabled\n\t\t\t} );\n\t\tcase actionTypes.LINK_DWELL:\n\t\t\t// New interaction\n\t\t\tif ( action.el !== state.activeLink ) {\n\t\t\t\treturn nextState( state, {\n\t\t\t\t\tactiveLink: action.el,\n\t\t\t\t\tactiveEvent: action.event,\n\t\t\t\t\tactiveToken: action.token,\n\n\t\t\t\t\t// When the user dwells on a link with their keyboard, a preview is\n\t\t\t\t\t// renderered, and then dwells on another link, the ABANDON_END\n\t\t\t\t\t// action will be ignored.\n\t\t\t\t\t//\n\t\t\t\t\t// Ensure that all the preview is hidden.\n\t\t\t\t\tshouldShow: false,\n\n\t\t\t\t\tisUserDwelling: true\n\t\t\t\t} );\n\t\t\t} else {\n\t\t\t\t// Dwelling back into the same link\n\t\t\t\treturn nextState( state, {\n\t\t\t\t\tisUserDwelling: true\n\t\t\t\t} );\n\t\t\t}\n\n\t\tcase actionTypes.ABANDON_END:\n\t\t\tif ( action.token === state.activeToken && !state.isUserDwelling ) {\n\t\t\t\treturn nextState( state, {\n\t\t\t\t\tactiveLink: undefined,\n\t\t\t\t\tactiveToken: undefined,\n\t\t\t\t\tactiveEvent: undefined,\n\t\t\t\t\tfetchResponse: undefined,\n\t\t\t\t\tshouldShow: false\n\t\t\t\t} );\n\t\t\t}\n\t\t\treturn state;\n\n\t\tcase actionTypes.PREVIEW_DWELL:\n\t\t\treturn nextState( state, {\n\t\t\t\tisUserDwelling: true\n\t\t\t} );\n\n\t\tcase actionTypes.ABANDON_START:\n\t\t\treturn nextState( state, {\n\t\t\t\tisUserDwelling: false\n\t\t\t} );\n\n\t\tcase actionTypes.FETCH_START:\n\t\t\treturn nextState( state, {\n\t\t\t\tfetchResponse: undefined\n\t\t\t} );\n\t\tcase actionTypes.FETCH_COMPLETE:\n\t\t\tif ( action.token === state.activeToken ) {\n\t\t\t\treturn nextState( state, {\n\t\t\t\t\tfetchResponse: action.result,\n\t\t\t\t\tshouldShow: state.isUserDwelling\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\t/* falls through */\n\t\tdefault:\n\t\t\treturn state;\n\t}\n}\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/reducers/preview.js\n// module id = ./src/reducers/preview.js\n// module chunks = 0","import actionTypes from '../actionTypes';\nimport nextState from './nextState';\n\n/**\n * Reducer for actions that modify the state of the settings\n *\n * @param {Object} state\n * @param {Object} action\n * @return {Object} state after action\n */\nexport default function settings( state, action ) {\n\tif ( state === undefined ) {\n\t\tstate = {\n\t\t\tshouldShow: false,\n\t\t\tshowHelp: false,\n\t\t\tshouldShowFooterLink: false\n\t\t};\n\t}\n\n\tswitch ( action.type ) {\n\t\tcase actionTypes.SETTINGS_SHOW:\n\t\t\treturn nextState( state, {\n\t\t\t\tshouldShow: true,\n\t\t\t\tshowHelp: false\n\t\t\t} );\n\t\tcase actionTypes.SETTINGS_HIDE:\n\t\t\treturn nextState( state, {\n\t\t\t\tshouldShow: false,\n\t\t\t\tshowHelp: false\n\t\t\t} );\n\t\tcase actionTypes.SETTINGS_CHANGE:\n\t\t\treturn action.wasEnabled === action.enabled ?\n\t\t\t\t// If the setting is the same, just hide the dialogs\n\t\t\t\tnextState( state, {\n\t\t\t\t\tshouldShow: false\n\t\t\t\t} ) :\n\t\t\t\t// If the settings have changed...\n\t\t\t\tnextState( state, {\n\t\t\t\t\t// If we enabled, we just hide directly, no help\n\t\t\t\t\t// If we disabled, keep it showing and let the ui show the help.\n\t\t\t\t\tshouldShow: !action.enabled,\n\t\t\t\t\tshowHelp: !action.enabled,\n\n\t\t\t\t\t// Since the footer link is only ever shown to anonymous users (see\n\t\t\t\t\t// the BOOT case below), state.userIsAnon is always truthy here.\n\t\t\t\t\tshouldShowFooterLink: !action.enabled\n\t\t\t\t} );\n\n\t\tcase actionTypes.BOOT:\n\t\t\treturn nextState( state, {\n\t\t\t\tshouldShowFooterLink: action.user.isAnon && !action.isEnabled\n\t\t\t} );\n\t\tdefault:\n\t\t\treturn state;\n\t}\n}\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/reducers/settings.js\n// module id = ./src/reducers/settings.js\n// module chunks = 0","import actionTypes from './../actionTypes';\nimport nextState from './nextState';\n\n/**\n * Reducer for actions that may result in an event being logged via statsv.\n *\n * @param {Object} state\n * @param {Object} action\n * @return {Object} state after action\n */\nexport default function statsv( state, action ) {\n\tstate = state || {};\n\n\tswitch ( action.type ) {\n\t\tcase actionTypes.FETCH_START:\n\t\t\treturn nextState( state, {\n\t\t\t\tfetchStartedAt: action.timestamp\n\t\t\t} );\n\n\t\tcase actionTypes.FETCH_END:\n\t\t\treturn nextState( state, {\n\t\t\t\taction: 'timing.PagePreviewsApiResponse',\n\t\t\t\tdata: action.timestamp - state.fetchStartedAt\n\t\t\t} );\n\n\t\tcase actionTypes.FETCH_FAILED:\n\t\t\treturn nextState( state, {\n\t\t\t\taction: 'counter.PagePreviewsApiFailure',\n\t\t\t\tdata: 1\n\t\t\t} );\n\n\t\tcase actionTypes.LINK_DWELL:\n\t\t\treturn nextState( state, {\n\t\t\t\tlinkDwellStartedAt: action.timestamp\n\t\t\t} );\n\n\t\tcase actionTypes.PREVIEW_SHOW:\n\t\t\treturn nextState( state, {\n\t\t\t\taction: 'timing.PagePreviewsPreviewShow',\n\t\t\t\tdata: action.timestamp - state.linkDwellStartedAt\n\t\t\t} );\n\n\t\tcase actionTypes.STATSV_LOGGED:\n\t\t\treturn nextState( state, {\n\t\t\t\taction: null,\n\t\t\t\tdata: null\n\t\t\t} );\n\n\t\tdefault:\n\t\t\treturn state;\n\t}\n}\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/reducers/statsv.js\n// module id = ./src/reducers/statsv.js\n// module chunks = 0","/**\n * @module title\n */\n\nvar mw = window.mediaWiki;\n\n/**\n * Gets the title of a local page from an href given some configuration.\n *\n * @param {String} href\n * @param {mw.Map} config\n * @return {String|undefined}\n */\nexport function getTitle( href, config ) {\n\tvar linkHref,\n\t\tmatches,\n\t\tqueryLength,\n\t\ttitleRegex = new RegExp( mw.RegExp.escape( config.get( 'wgArticlePath' ) )\n\t\t\t.replace( '\\\\$1', '(.+)' ) );\n\n\t// Skip every URI that mw.Uri cannot parse\n\ttry {\n\t\tlinkHref = new mw.Uri( href );\n\t} catch ( e ) {\n\t\treturn undefined;\n\t}\n\n\t// External links\n\tif ( linkHref.host !== location.hostname ) {\n\t\treturn undefined;\n\t}\n\n\tqueryLength = Object.keys( linkHref.query ).length;\n\n\t// No query params (pretty URL)\n\tif ( !queryLength ) {\n\t\tmatches = titleRegex.exec( linkHref.path );\n\t\treturn matches ? decodeURIComponent( matches[ 1 ] ) : undefined;\n\t} else if ( queryLength === 1 && linkHref.query.hasOwnProperty( 'title' ) ) {\n\t\t// URL is not pretty, but only has a `title` parameter\n\t\treturn linkHref.query.title;\n\t}\n\n\treturn undefined;\n}\n\n/**\n * Given a page title it will return the mediawiki.Title if it is an eligible\n * link for showing page previews, null otherwise\n *\n * @param {String} title page title to check if it should show preview\n * @param {Number[]} contentNamespaces contentNamespaces as specified in\n * wgContentNamespaces\n * @returns {mw.Title|null}\n */\nexport function isValid( title, contentNamespaces ) {\n\tvar mwTitle;\n\n\tif ( !title ) {\n\t\treturn null;\n\t}\n\n\t// Is title in a content namespace?\n\tmwTitle = mw.Title.newFromText( title );\n\tif ( mwTitle && ( $.inArray( mwTitle.namespace, contentNamespaces ) >= 0 ) ) {\n\t\treturn mwTitle;\n\t}\n\n\treturn null;\n}\n\n/**\n * Return a mw.Title from a HTMLElement if valid for hovercards. Convenience\n * method\n *\n * @param {Element} el\n * @param {mw.Map} config\n * @return {mw.Title|null}\n */\nexport function fromElement( el, config ) {\n\treturn isValid( getTitle( el.href, config ), config.get( 'wgContentNamespaces' ) );\n}\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/title.js\n// module id = ./src/title.js\n// module chunks = 0","/**\n * @module renderer\n */\n\nimport wait from '../wait';\n\nvar mw = window.mediaWiki,\n\t$ = jQuery,\n\tSIZES = {\n\t\tportraitImage: {\n\t\t\th: 250, // Exact height\n\t\t\tw: 203 // Max width\n\t\t},\n\t\tlandscapeImage: {\n\t\t\th: 200, // Max height\n\t\t\tw: 320 // Exact Width\n\t\t},\n\t\tlandscapePopupWidth: 450,\n\t\tportraitPopupWidth: 320,\n\t\tpokeySize: 8 // Height of the pokey.\n\t},\n\t$window = $( window );\n\n/**\n * Extracted from `mw.popups.createSVGMasks`.\n * @private\n * @param {Object} container DOM object to which pokey masks are appended\n */\nexport function createPokeyMasks( container ) {\n\t$( '<div>' )\n\t\t.attr( 'id', 'mwe-popups-svg' )\n\t\t.html(\n\t\t\t'<svg width=\"0\" height=\"0\">' +\n\t\t\t\t'<defs>' +\n\t\t\t\t\t'<clippath id=\"mwe-popups-mask\">' +\n\t\t\t\t\t\t'<polygon points=\"0 8, 10 8, 18 0, 26 8, 1000 8, 1000 1000, 0 1000\"/>' +\n\t\t\t\t\t'</clippath>' +\n\t\t\t\t\t'<clippath id=\"mwe-popups-mask-flip\">' +\n\t\t\t\t\t\t'<polygon points=\"0 8, 274 8, 282 0, 290 8, 1000 8, 1000 1000, 0 1000\"/>' +\n\t\t\t\t\t'</clippath>' +\n\t\t\t\t\t'<clippath id=\"mwe-popups-landscape-mask\">' +\n\t\t\t\t\t\t'<polygon points=\"0 8, 174 8, 182 0, 190 8, 1000 8, 1000 1000, 0 1000\"/>' +\n\t\t\t\t\t'</clippath>' +\n\t\t\t\t\t'<clippath id=\"mwe-popups-landscape-mask-flip\">' +\n\t\t\t\t\t\t'<polygon points=\"0 0, 1000 0, 1000 242, 190 242, 182 250, 174 242, 0 242\"/>' +\n\t\t\t\t\t'</clippath>' +\n\t\t\t\t'</defs>' +\n\t\t\t'</svg>'\n\t\t)\n\t\t.appendTo( container );\n}\n\n/**\n * Initializes the renderer.\n */\nexport function init() {\n\tcreatePokeyMasks( document.body );\n}\n\n/**\n * The model of how a view is rendered, which is constructed from a response\n * from the gateway.\n *\n * TODO: Rename `isTall` to `isPortrait`.\n *\n * @typedef {Object} ext.popups.Preview\n * @property {jQuery} el\n * @property {Boolean} hasThumbnail\n * @property {Object} thumbnail\n * @property {Boolean} isTall Sugar around\n * `preview.hasThumbnail && thumbnail.isTall`\n */\n\n/**\n * Renders a preview given data from the {@link gateway Gateway}.\n * The preview is rendered and added to the DOM but will remain hidden until\n * the `show` method is called.\n *\n * Previews are rendered at:\n *\n * # The position of the mouse when the user dwells on the link with their\n * mouse.\n * # The centermost point of the link when the user dwells on the link with\n * their keboard or other assistive device.\n *\n * Since the content of the preview doesn't change but its position might, we\n * distinguish between \"rendering\" - generating HTML from a MediaWiki API\n * response - and \"showing/hiding\" - positioning the layout and changing its\n * orientation, if necessary.\n *\n * @param {ext.popups.PreviewModel} model\n * @return {ext.popups.Preview}\n */\nexport function render( model ) {\n\tvar preview = model.extract === undefined ? createEmptyPreview( model ) : createPreview( model );\n\n\treturn {\n\n\t\t/**\n\t\t * Shows the preview given an event representing the user's interaction\n\t\t * with the active link, e.g. an instance of\n\t\t * [MouseEvent](https://developer.mozilla.org/en/docs/Web/API/MouseEvent).\n\t\t *\n\t\t * See `show` for more detail.\n\t\t *\n\t\t * @param {Event} event\n\t\t * @param {Object} boundActions The\n\t\t * [bound action creators](http://redux.js.org/docs/api/bindActionCreators.html)\n\t\t * that were (likely) created in [boot.js](./boot.js).\n\t\t * @param {String} token The unique token representing the link interaction\n\t\t * that resulted in showing the preview\n\t\t * @return {jQuery.Promise}\n\t\t */\n\t\tshow: function ( event, boundActions, token ) {\n\t\t\treturn show(\n\t\t\t\tpreview, event, $( event.target ), boundActions, token,\n\t\t\t\tdocument.body\n\t\t\t);\n\t\t},\n\n\t\t/**\n\t\t * Hides the preview.\n\t\t *\n\t\t * See `hide` for more detail.\n\t\t *\n\t\t * @return {jQuery.Promise}\n\t\t */\n\t\thide: function () {\n\t\t\treturn hide( preview );\n\t\t}\n\t};\n}\n\n/**\n * Creates an instance of the DTO backing a preview.\n *\n * @param {ext.popups.PreviewModel} model\n * @return {ext.popups.Preview}\n */\nexport function createPreview( model ) {\n\tvar templateData,\n\t\tthumbnail = createThumbnail( model.thumbnail ),\n\t\thasThumbnail = thumbnail !== null,\n\t\textract = model.extract,\n\t\t$el;\n\n\ttemplateData = $.extend( {}, model, {\n\t\thasThumbnail: hasThumbnail\n\t} );\n\n\t$el = mw.template.get( 'ext.popups', 'preview.mustache' )\n\t\t.render( templateData );\n\n\tif ( hasThumbnail ) {\n\t\t$el.find( '.mwe-popups-discreet' ).append( thumbnail.el );\n\t}\n\tif ( extract ) {\n\t\t$el.find( '.mwe-popups-extract' ).append( extract );\n\t}\n\n\treturn {\n\t\tel: $el,\n\t\thasThumbnail: hasThumbnail,\n\t\tthumbnail: thumbnail,\n\t\tisTall: hasThumbnail && thumbnail.isTall\n\t};\n}\n\n/**\n * Creates an instance of the DTO backing a preview. In this case the DTO\n * represents a generic preview, which covers the following scenarios:\n *\n * * The page doesn't exist, i.e. the user hovered over a redlink or a\n * redirect to a page that doesn't exist.\n * * The page doesn't have a viable extract.\n *\n * @param {ext.popups.PreviewModel} model\n * @return {ext.popups.Preview}\n */\nexport function createEmptyPreview( model ) {\n\tvar templateData,\n\t\t$el;\n\n\ttemplateData = $.extend( {}, model, {\n\t\textractMsg: mw.msg( 'popups-preview-no-preview' ),\n\t\treadMsg: mw.msg( 'popups-preview-footer-read' )\n\t} );\n\n\t$el = mw.template.get( 'ext.popups', 'preview-empty.mustache' )\n\t\t.render( templateData );\n\n\treturn {\n\t\tel: $el,\n\t\thasThumbnail: false,\n\t\tisTall: false\n\t};\n}\n\n/**\n * Shows the preview.\n *\n * Extracted from `mw.popups.render.openPopup`.\n *\n * TODO: From the perspective of the client, there's no need to distinguish\n * between renderering and showing a preview. Merge #render and Preview#show.\n *\n * @param {ext.popups.Preview} preview\n * @param {Event} event\n * @param {jQuery} $link event target\n * @param {ext.popups.PreviewBehavior} behavior\n * @param {String} token\n * @param {Object} container DOM object to which pokey masks are appended\n * @return {jQuery.Promise} A promise that resolves when the promise has faded\n * in\n */\nexport function show( preview, event, $link, behavior, token, container ) {\n\tvar layout = createLayout(\n\t\tpreview.isTall,\n\t\t{\n\t\t\tpageX: event.pageX,\n\t\t\tpageY: event.pageY,\n\t\t\tclientY: event.clientY\n\t\t},\n\t\t{\n\t\t\tclientRects: $link.get( 0 ).getClientRects(),\n\t\t\toffset: $link.offset(),\n\t\t\twidth: $link.width(),\n\t\t\theight: $link.height()\n\t\t},\n\t\t{\n\t\t\tscrollTop: $window.scrollTop(),\n\t\t\twidth: $window.width(),\n\t\t\theight: $window.height()\n\t\t},\n\t\tSIZES.pokeySize\n\t);\n\n\tpreview.el.appendTo( container );\n\n\tlayoutPreview(\n\t\tpreview, layout, getClasses( preview, layout ),\n\t\tSIZES.landscapeImage.h, SIZES.pokeySize\n\t);\n\n\tpreview.el.show();\n\n\treturn wait( 200 )\n\t\t.then( function () {\n\t\t\tbindBehavior( preview, behavior );\n\t\t} )\n\t\t.then( function () {\n\t\t\tbehavior.previewShow( token );\n\t\t} );\n}\n\n/**\n * Binds the behavior to the interactive elements of the preview.\n *\n * @param {ext.popups.Preview} preview\n * @param {ext.popups.PreviewBehavior} behavior\n */\nexport function bindBehavior( preview, behavior ) {\n\tpreview.el.hover( behavior.previewDwell, behavior.previewAbandon );\n\n\tpreview.el.click( behavior.click );\n\n\tpreview.el.find( '.mwe-popups-settings-icon' )\n\t\t.attr( 'href', behavior.settingsUrl )\n\t\t.click( function ( event ) {\n\t\t\tevent.stopPropagation();\n\n\t\t\tbehavior.showSettings( event );\n\t\t} );\n}\n\n/**\n * Extracted from `mw.popups.render.closePopup`.\n *\n * @param {ext.popups.Preview} preview\n * @return {jQuery.Promise} A promise that resolves when the preview has faded\n * out\n */\nexport function hide( preview ) {\n\tvar fadeInClass,\n\t\tfadeOutClass;\n\n\t// FIXME: This method clearly needs access to the layout of the preview.\n\tfadeInClass = ( preview.el.hasClass( 'mwe-popups-fade-in-up' ) ) ?\n\t\t'mwe-popups-fade-in-up' :\n\t\t'mwe-popups-fade-in-down';\n\n\tfadeOutClass = ( fadeInClass === 'mwe-popups-fade-in-up' ) ?\n\t\t'mwe-popups-fade-out-down' :\n\t\t'mwe-popups-fade-out-up';\n\n\tpreview.el\n\t\t.removeClass( fadeInClass )\n\t\t.addClass( fadeOutClass );\n\n\treturn wait( 150 ).then( function () {\n\t\tpreview.el.remove();\n\t} );\n}\n\n/**\n * @typedef {Object} ext.popups.Thumbnail\n * @property {Element} el\n * @property {Boolean} isTall Whether or not the thumbnail is portrait\n */\n\n/**\n * Creates a thumbnail from the representation of a thumbnail returned by the\n * PageImages MediaWiki API query module.\n *\n * If there's no thumbnail, the thumbnail is too small, or the thumbnail's URL\n * contains characters that could be used to perform an\n * [XSS attack via CSS](https://www.owasp.org/index.php/Testing_for_CSS_Injection_(OTG-CLIENT-005)),\n * then `null` is returned.\n *\n * Extracted from `mw.popups.renderer.article.createThumbnail`.\n *\n * @param {Object} rawThumbnail\n * @return {ext.popups.Thumbnail|null}\n */\nexport function createThumbnail( rawThumbnail ) {\n\tvar tall, thumbWidth, thumbHeight,\n\t\tx, y, width, height, clipPath,\n\t\tdevicePixelRatio = $.bracketedDevicePixelRatio();\n\n\tif ( !rawThumbnail ) {\n\t\treturn null;\n\t}\n\n\ttall = rawThumbnail.width < rawThumbnail.height;\n\tthumbWidth = rawThumbnail.width / devicePixelRatio;\n\tthumbHeight = rawThumbnail.height / devicePixelRatio;\n\n\tif (\n\t\t// Image too small for landscape display\n\t\t( !tall && thumbWidth < SIZES.landscapeImage.w ) ||\n\t\t// Image too small for portrait display\n\t\t( tall && thumbHeight < SIZES.portraitImage.h ) ||\n\t\t// These characters in URL that could inject CSS and thus JS\n\t\t(\n\t\t\trawThumbnail.source.indexOf( '\\\\' ) > -1 ||\n\t\t\trawThumbnail.source.indexOf( '\\'' ) > -1 ||\n\t\t\trawThumbnail.source.indexOf( '\\\"' ) > -1\n\t\t)\n\t) {\n\t\treturn null;\n\t}\n\n\tif ( tall ) {\n\t\tx = ( thumbWidth > SIZES.portraitImage.w ) ?\n\t\t\t( ( thumbWidth - SIZES.portraitImage.w ) / -2 ) :\n\t\t\t( SIZES.portraitImage.w - thumbWidth );\n\t\ty = ( thumbHeight > SIZES.portraitImage.h ) ?\n\t\t\t( ( thumbHeight - SIZES.portraitImage.h ) / -2 ) : 0;\n\t\twidth = SIZES.portraitImage.w;\n\t\theight = SIZES.portraitImage.h;\n\t} else {\n\t\tx = 0;\n\t\ty = ( thumbHeight > SIZES.landscapeImage.h ) ?\n\t\t\t( ( thumbHeight - SIZES.landscapeImage.h ) / -2 ) : 0;\n\t\twidth = SIZES.landscapeImage.w + 3;\n\t\theight = ( thumbHeight > SIZES.landscapeImage.h ) ?\n\t\t\tSIZES.landscapeImage.h : thumbHeight;\n\t\tclipPath = 'mwe-popups-mask';\n\t}\n\n\treturn {\n\t\tel: createThumbnailElement(\n\t\t\ttall ? 'mwe-popups-is-tall' : 'mwe-popups-is-not-tall',\n\t\t\trawThumbnail.source,\n\t\t\tx,\n\t\t\ty,\n\t\t\tthumbWidth,\n\t\t\tthumbHeight,\n\t\t\twidth,\n\t\t\theight,\n\t\t\tclipPath\n\t\t),\n\t\tisTall: tall,\n\t\twidth: thumbWidth,\n\t\theight: thumbHeight\n\t};\n}\n\n/**\n * Creates the SVG image element that represents the thumbnail.\n *\n * This function is distinct from `createThumbnail` as it abstracts away some\n * browser issues that are uncovered when manipulating elements across\n * namespaces.\n *\n * @param {String} className\n * @param {String} url\n * @param {Number} x\n * @param {Number} y\n * @param {Number} thumbnailWidth\n * @param {Number} thumbnailHeight\n * @param {Number} width\n * @param {Number} height\n * @param {String} clipPath\n * @return {jQuery}\n */\nexport function createThumbnailElement( className, url, x, y, thumbnailWidth, thumbnailHeight, width, height, clipPath ) {\n\tvar $thumbnailSVGImage, $thumbnail,\n\t\tnsSvg = 'http://www.w3.org/2000/svg',\n\t\tnsXlink = 'http://www.w3.org/1999/xlink';\n\n\t$thumbnailSVGImage = $( document.createElementNS( nsSvg, 'image' ) );\n\t$thumbnailSVGImage[ 0 ].setAttributeNS( nsXlink, 'href', url );\n\t$thumbnailSVGImage\n\t\t.addClass( className )\n\t\t.attr( {\n\t\t\tx: x,\n\t\t\ty: y,\n\t\t\twidth: thumbnailWidth,\n\t\t\theight: thumbnailHeight,\n\t\t\t'clip-path': 'url(#' + clipPath + ')'\n\t\t} );\n\n\t$thumbnail = $( document.createElementNS( nsSvg, 'svg' ) )\n\t\t.attr( {\n\t\t\txmlns: nsSvg,\n\t\t\twidth: width,\n\t\t\theight: height\n\t\t} )\n\t\t.append( $thumbnailSVGImage );\n\n\treturn $thumbnail;\n}\n\n/**\n * Represents the layout of a preview, which consists of a position (`offset`)\n * and whether or not the preview should be flipped horizontally or\n * vertically (`flippedX` and `flippedY` respectively).\n *\n * @typedef {Object} ext.popups.PreviewLayout\n * @property {Object} offset\n * @property {number} offset.top\n * @property {number} offset.left\n * @property {Boolean} flippedX\n * @property {Boolean} flippedY\n */\n\n/**\n * @param {isPreviewTall} isPreviewTall\n * @param {Object} eventData Data related to the event that triggered showing a popup\n * @param {number} eventData.pageX\n * @param {number} eventData.pageY\n * @param {number} eventData.clientY\n * @param {Object} linkData Data related to the link that’s used for showing a popup\n * @param {ClientRectList} linkData.clientRects list of rectangles defined by four edges\n * @param {Object} linkData.offset\n * @param {number} linkData.width\n * @param {number} linkData.height\n * @param {Object} windowData Data related to the window\n * @param {number} windowData.scrollTop\n * @param {number} windowData.width\n * @param {number} windowData.height\n * @param {number} pokeySize Space reserved for the pokey\n * @return {ext.popups.PreviewLayout}\n */\nexport function createLayout( isPreviewTall, eventData, linkData, windowData, pokeySize ) {\n\tvar flippedX = false,\n\t\tflippedY = false,\n\t\toffsetTop = ( eventData.pageY ) ? // If it was a mouse event\n\t\t\t// Position according to mouse\n\t\t\t// Since client rectangles are relative to the viewport,\n\t\t\t// take scroll position into account.\n\t\t\tgetClosestYPosition(\n\t\t\t\teventData.pageY - windowData.scrollTop,\n\t\t\t\tlinkData.clientRects,\n\t\t\t\tfalse\n\t\t\t) + windowData.scrollTop + pokeySize :\n\t\t\t// Position according to link position or size\n\t\t\tlinkData.offset.top + linkData.height + pokeySize,\n\t\tclientTop = ( eventData.clientY ) ?\n\t\t\teventData.clientY :\n\t\t\toffsetTop,\n\t\toffsetLeft = ( eventData.pageX ) ?\n\t\t\teventData.pageX :\n\t\t\tlinkData.offset.left;\n\n\t// X Flip\n\tif ( offsetLeft > ( windowData.width / 2 ) ) {\n\t\toffsetLeft += ( !eventData.pageX ) ? linkData.width : 0;\n\t\toffsetLeft -= !isPreviewTall ?\n\t\t\tSIZES.portraitPopupWidth :\n\t\t\tSIZES.landscapePopupWidth;\n\t\tflippedX = true;\n\t}\n\n\tif ( eventData.pageX ) {\n\t\toffsetLeft += ( flippedX ) ? 20 : -20;\n\t}\n\n\t// Y Flip\n\tif ( clientTop > ( windowData.height / 2 ) ) {\n\t\tflippedY = true;\n\n\t\t// Mirror the positioning of the preview when there's no \"Y flip\": rest\n\t\t// the pokey on the edge of the link's bounding rectangle. In this case\n\t\t// the edge is the top-most.\n\t\toffsetTop = linkData.offset.top;\n\n\t\t// Change the Y position to the top of the link\n\t\tif ( eventData.pageY ) {\n\t\t\t// Since client rectangles are relative to the viewport,\n\t\t\t// take scroll position into account.\n\t\t\toffsetTop = getClosestYPosition(\n\t\t\t\teventData.pageY - windowData.scrollTop,\n\t\t\t\tlinkData.clientRects,\n\t\t\t\ttrue\n\t\t\t) + windowData.scrollTop;\n\t\t}\n\n\t\toffsetTop -= pokeySize;\n\t}\n\n\treturn {\n\t\toffset: {\n\t\t\ttop: offsetTop,\n\t\t\tleft: offsetLeft\n\t\t},\n\t\tflippedX: flippedX,\n\t\tflippedY: flippedY\n\t};\n}\n\n/**\n * Generates a list of declarative CSS classes that represent the layout of\n * the preview.\n *\n * @param {ext.popups.Preview} preview\n * @param {ext.popups.PreviewLayout} layout\n * @return {String[]}\n */\nexport function getClasses( preview, layout ) {\n\tvar classes = [];\n\n\tif ( layout.flippedY ) {\n\t\tclasses.push( 'mwe-popups-fade-in-down' );\n\t} else {\n\t\tclasses.push( 'mwe-popups-fade-in-up' );\n\t}\n\n\tif ( layout.flippedY && layout.flippedX ) {\n\t\tclasses.push( 'flipped_x_y' );\n\t}\n\n\tif ( layout.flippedY && !layout.flippedX ) {\n\t\tclasses.push( 'flipped_y' );\n\t}\n\n\tif ( layout.flippedX && !layout.flippedY ) {\n\t\tclasses.push( 'flipped_x' );\n\t}\n\n\tif ( ( !preview.hasThumbnail || preview.isTall ) && !layout.flippedY ) {\n\t\tclasses.push( 'mwe-popups-no-image-tri' );\n\t}\n\n\tif ( ( preview.hasThumbnail && !preview.isTall ) && !layout.flippedY ) {\n\t\tclasses.push( 'mwe-popups-image-tri' );\n\t}\n\n\tif ( preview.isTall ) {\n\t\tclasses.push( 'mwe-popups-is-tall' );\n\t} else {\n\t\tclasses.push( 'mwe-popups-is-not-tall' );\n\t}\n\n\treturn classes;\n}\n\n/**\n * Lays out the preview given the layout.\n *\n * If the preview should be oriented differently, then the pokey is updated,\n * e.g. if the preview should be flipped vertically, then the pokey is\n * removed.\n *\n * If the thumbnail is landscape and isn't the full height of the thumbnail\n * container, then pull the extract up to keep whitespace consistent across\n * previews.\n *\n * @param {ext.popups.Preview} preview\n * @param {ext.popups.PreviewLayout} layout\n * @param {string[]} classes class names used for layout out the preview\n * @param {number} predefinedLandscapeImageHeight landscape image height\n * @param {number} pokeySize\n */\nexport function layoutPreview( preview, layout, classes, predefinedLandscapeImageHeight, pokeySize ) {\n\tvar popup = preview.el,\n\t\tisTall = preview.isTall,\n\t\thasThumbnail = preview.hasThumbnail,\n\t\tthumbnail = preview.thumbnail,\n\t\tflippedY = layout.flippedY,\n\t\tflippedX = layout.flippedX,\n\t\toffsetTop = layout.offset.top;\n\n\tif (\n\t\t!flippedY && !isTall && hasThumbnail &&\n\t\t\tthumbnail.height < predefinedLandscapeImageHeight\n\t) {\n\t\tpopup.find( '.mwe-popups-extract' ).css(\n\t\t\t'margin-top',\n\t\t\tthumbnail.height - pokeySize\n\t\t);\n\t}\n\n\tpopup.addClass( classes.join( ' ' ) );\n\n\tif ( flippedY ) {\n\t\toffsetTop -= popup.outerHeight();\n\t}\n\n\tpopup.css( {\n\t\ttop: offsetTop,\n\t\tleft: layout.offset.left + 'px'\n\t} );\n\n\tif ( flippedY && hasThumbnail ) {\n\t\tpopup.find( 'image' )[ 0 ]\n\t\t\t.removeAttribute( 'clip-path' );\n\t}\n\n\tif ( flippedY && flippedX && hasThumbnail && isTall ) {\n\t\tpopup.find( 'image' )[ 0 ]\n\t\t\t.setAttribute( 'clip-path', 'url(#mwe-popups-landscape-mask-flip)' );\n\t}\n\n\tif ( flippedX && !flippedY && hasThumbnail && !isTall ) {\n\t\tpopup.find( 'image' )[ 0 ]\n\t\t\t.setAttribute( 'clip-path', 'url(#mwe-popups-mask-flip)' );\n\t}\n\n\tif ( flippedX && !flippedY && hasThumbnail && isTall ) {\n\t\tpopup.removeClass( 'mwe-popups-no-image-tri' )\n\t\t\t.find( 'image' )[ 0 ]\n\t\t\t.setAttribute( 'clip-path', 'url(#mwe-popups-landscape-mask)' );\n\t}\n}\n\n/**\n * Given the rectangular box(es) find the 'y' boundary of the closest\n * rectangle to the point 'y'. The point 'y' is the location of the mouse\n * on the 'y' axis and the rectangular box(es) are the borders of the\n * element over which the mouse is located. There will be more than one\n * rectangle in case the element spans multiple lines.\n *\n * In the majority of cases the mouse pointer will be inside a rectangle.\n * However, some browsers (i.e. Chrome) trigger a hover action even when\n * the mouse pointer is just outside a bounding rectangle. That's why\n * we need to look at all rectangles and not just the rectangle that\n * encloses the point.\n *\n * @private\n * @param {Number} y the point for which the closest location is being\n * looked for\n * @param {ClientRectList} rects list of rectangles defined by four edges\n * @param {Boolean} [isTop] should the resulting rectangle's top 'y'\n * boundary be returned. By default the bottom 'y' value is returned.\n * @return {Number}\n */\nexport function getClosestYPosition( y, rects, isTop ) {\n\tvar result,\n\t\tdeltaY,\n\t\tminY = null;\n\n\t$.each( rects, function ( i, rect ) {\n\t\tdeltaY = Math.abs( y - rect.top + y - rect.bottom );\n\n\t\tif ( minY === null || minY > deltaY ) {\n\t\t\tminY = deltaY;\n\t\t\t// Make sure the resulting point is at or outside the rectangle\n\t\t\t// boundaries.\n\t\t\tresult = ( isTop ) ? Math.floor( rect.top ) : Math.ceil( rect.bottom );\n\t\t}\n\t} );\n\n\treturn result;\n}\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/ui/renderer.js\n// module id = ./src/ui/renderer.js\n// module chunks = 0","/**\n * @module settingsDialog\n */\n\nvar mw = window.mediaWiki,\n\t$ = jQuery;\n\n/**\n * Creates a render function that will create the settings dialog and return\n * a set of methods to operate on it\n * @returns {Function} render function\n */\nexport default function createSettingsDialogRenderer() {\n\n\t/**\n\t * Cached settings dialog\n\t *\n\t * @type {jQuery}\n\t */\n\tvar $dialog,\n\t\t/**\n\t\t * Cached settings overlay\n\t\t *\n\t\t * @type {jQuery}\n\t\t */\n\t\t$overlay;\n\n\t/**\n\t * Renders the relevant form and labels in the settings dialog\n\t * @param {Object} boundActions\n\t * @returns {Object} object with methods to affect the rendered UI\n\t */\n\treturn function ( boundActions ) {\n\n\t\tif ( !$dialog ) {\n\t\t\t$dialog = createSettingsDialog();\n\t\t\t$overlay = $( '<div>' ).addClass( 'mwe-popups-overlay' );\n\n\t\t\t// Setup event bindings\n\n\t\t\t$dialog.find( '.save' ).click( function () {\n\t\t\t\t// Find the selected value (simple|advanced|off)\n\t\t\t\tvar selected = getSelectedSetting( $dialog ),\n\t\t\t\t\t// Only simple means enabled, advanced is disabled in favor of\n\t\t\t\t\t// NavPops and off means disabled.\n\t\t\t\t\tenabled = selected === 'simple';\n\n\t\t\t\tboundActions.saveSettings( enabled );\n\t\t\t} );\n\t\t\t$dialog.find( '.close, .okay' ).click( boundActions.hideSettings );\n\t\t}\n\n\t\treturn {\n\t\t\t/**\n\t\t\t * Append the dialog and overlay to a DOM element\n\t\t\t * @param {HTMLElement} el\n\t\t\t */\n\t\t\tappendTo: function ( el ) {\n\t\t\t\t$overlay.appendTo( el );\n\t\t\t\t$dialog.appendTo( el );\n\t\t\t},\n\n\t\t\t/**\n\t\t\t * Show the settings element and position it correctly\n\t\t\t */\n\t\t\tshow: function () {\n\t\t\t\tvar h = $( window ).height(),\n\t\t\t\t\tw = $( window ).width();\n\n\t\t\t\t$overlay.show();\n\n\t\t\t\t// FIXME: Should recalc on browser resize\n\t\t\t\t$dialog\n\t\t\t\t\t.show()\n\t\t\t\t\t.css( 'left', ( w - $dialog.outerWidth( true ) ) / 2 )\n\t\t\t\t\t.css( 'top', ( h - $dialog.outerHeight( true ) ) / 2 );\n\t\t\t},\n\n\t\t\t/**\n\t\t\t * Hide the settings dialog.\n\t\t\t */\n\t\t\thide: function () {\n\t\t\t\t$overlay.hide();\n\t\t\t\t$dialog.hide();\n\t\t\t},\n\n\t\t\t/**\n\t\t\t * Toggle the help dialog on or off\n\t\t\t * @param {Boolean} visible if you want to show or hide the help dialog\n\t\t\t */\n\t\t\ttoggleHelp: function ( visible ) {\n\t\t\t\ttoggleHelp( $dialog, visible );\n\t\t\t},\n\n\t\t\t/**\n\t\t\t * Update the form depending on the enabled flag\n\t\t\t *\n\t\t\t * If false and no navpops, then checks 'off'\n\t\t\t * If true, then checks 'on'\n\t\t\t * If false, and there are navpops, then checks 'advanced'\n\t\t\t *\n\t\t\t * @param {Boolean} enabled if page previews are enabled\n\t\t\t */\n\t\t\tsetEnabled: function ( enabled ) {\n\t\t\t\tvar name = 'off';\n\t\t\t\tif ( enabled ) {\n\t\t\t\t\tname = 'simple';\n\t\t\t\t} else if ( isNavPopupsEnabled() ) {\n\t\t\t\t\tname = 'advanced';\n\t\t\t\t}\n\n\t\t\t\t// Check the appropiate radio button\n\t\t\t\t$dialog.find( '#mwe-popups-settings-' + name )\n\t\t\t\t\t.prop( 'checked', true );\n\t\t\t}\n\t\t};\n\t};\n}\n\n/**\n * Create the settings dialog\n *\n * @return {jQuery} settings dialog\n */\nfunction createSettingsDialog() {\n\tvar $el,\n\t\tpath = mw.config.get( 'wgExtensionAssetsPath' ) + '/Popups/resources/ext.popups/images/',\n\t\tchoices = [\n\t\t\t{\n\t\t\t\tid: 'simple',\n\t\t\t\tname: mw.msg( 'popups-settings-option-simple' ),\n\t\t\t\tdescription: mw.msg( 'popups-settings-option-simple-description' ),\n\t\t\t\timage: path + 'hovercard.svg',\n\t\t\t\tisChecked: true\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'advanced',\n\t\t\t\tname: mw.msg( 'popups-settings-option-advanced' ),\n\t\t\t\tdescription: mw.msg( 'popups-settings-option-advanced-description' ),\n\t\t\t\timage: path + 'navpop.svg'\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'off',\n\t\t\t\tname: mw.msg( 'popups-settings-option-off' )\n\t\t\t}\n\t\t];\n\n\tif ( !isNavPopupsEnabled() ) {\n\t\t// remove the advanced option\n\t\tchoices.splice( 1, 1 );\n\t}\n\n\t// render the template\n\t$el = mw.template.get( 'ext.popups', 'settings.mustache' ).render( {\n\t\theading: mw.msg( 'popups-settings-title' ),\n\t\tcloseLabel: mw.msg( 'popups-settings-cancel' ),\n\t\tsaveLabel: mw.msg( 'popups-settings-save' ),\n\t\thelpText: mw.msg( 'popups-settings-help' ),\n\t\tokLabel: mw.msg( 'popups-settings-help-ok' ),\n\t\tdescriptionText: mw.msg( 'popups-settings-description' ),\n\t\tchoices: choices\n\t} );\n\n\treturn $el;\n}\n\n/**\n * Get the selected value on the radio button\n *\n * @param {jQuery.Object} $el the element to extract the setting from\n * @return {String} Which should be (simple|advanced|off)\n */\nfunction getSelectedSetting( $el ) {\n\treturn $el.find(\n\t\t'input[name=mwe-popups-setting]:checked, #mwe-popups-settings'\n\t).val();\n}\n\n/**\n * Toggles the visibility between a form and the help\n * @param {jQuery.Object} $el element that contains form and help\n * @param {Boolean} visible if the help should be visible, or the form\n */\nfunction toggleHelp( $el, visible ) {\n\tvar $dialog = $( '#mwe-popups-settings' ),\n\t\tformSelectors = 'main, .save, .close',\n\t\thelpSelectors = '.mwe-popups-settings-help, .okay';\n\n\tif ( visible ) {\n\t\t$dialog.find( formSelectors ).hide();\n\t\t$dialog.find( helpSelectors ).show();\n\t} else {\n\t\t$dialog.find( formSelectors ).show();\n\t\t$dialog.find( helpSelectors ).hide();\n\t}\n}\n\n/**\n * Checks if the NavigationPopups gadget is enabled by looking at the global\n * variables\n * @returns {Boolean} if navpops was found to be enabled\n */\nfunction isNavPopupsEnabled() {\n\t/* global pg: false*/\n\treturn typeof pg !== 'undefined' && pg.fn.disablePopups !== undefined;\n}\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/ui/settingsDialog.js\n// module id = ./src/ui/settingsDialog.js\n// module chunks = 0","/**\n * @module userSettings\n */\n\n/**\n * @interface UserSettings\n *\n * @global\n */\n\nvar IS_ENABLED_KEY = 'mwe-popups-enabled',\n\tPREVIEW_COUNT_KEY = 'ext.popups.core.previewCount';\n\n/**\n * Creates an object whose methods encapsulate all interactions with the UA's\n * storage.\n *\n * @param {Object} storage The `mw.storage` singleton instance\n *\n * @return {UserSettings}\n */\nexport default function createUserSettings( storage ) {\n\treturn {\n\n\t\t/**\n\t\t * Gets whether the user has previously enabled Page Previews.\n\t\t *\n\t\t * N.B. that if the user hasn't previously enabled or disabled Page\n\t\t * Previews, i.e. userSettings.setIsEnabled(true), then they are treated as\n\t\t * if they have enabled them.\n\t\t *\n\t\t * @function\n\t\t * @name UserSettings#getIsEnabled\n\t\t * @return {Boolean}\n\t\t */\n\t\tgetIsEnabled: function () {\n\t\t\treturn storage.get( IS_ENABLED_KEY ) !== '0';\n\t\t},\n\n\t\t/**\n\t\t * Sets whether the user has enabled Page Previews.\n\t\t *\n\t\t * @function\n\t\t * @name UserSettings#setIsEnabled\n\t\t * @param {Boolean} isEnabled\n\t\t */\n\t\tsetIsEnabled: function ( isEnabled ) {\n\t\t\tstorage.set( IS_ENABLED_KEY, isEnabled ? '1' : '0' );\n\t\t},\n\n\t\t/**\n\t\t * Gets whether the user has previously enabled **or disabled** Page\n\t\t * Previews.\n\t\t *\n\t\t * @function\n\t\t * @name UserSettings#hasIsEnabled\n\t\t * @return {Boolean}\n\t\t */\n\t\thasIsEnabled: function () {\n\t\t\tvar value = storage.get( IS_ENABLED_KEY );\n\n\t\t\treturn Boolean( value ) !== false;\n\t\t},\n\n\t\t/**\n\t\t * Gets the number of previews that the user has seen.\n\t\t *\n\t\t * If the storage isn't available, then -1 is returned.\n\t\t * If the value in storage is not a number it will override stored value to 0\n\t\t *\n\t\t * @function\n\t\t * @name UserSettings#getPreviewCount\n\t\t * @return {Number}\n\t\t */\n\t\tgetPreviewCount: function () {\n\t\t\tvar result = storage.get( PREVIEW_COUNT_KEY ), count;\n\n\t\t\tif ( result === false ) {\n\t\t\t\treturn -1;\n\t\t\t} else if ( result === null ) {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tcount = parseInt( result, 10 );\n\n\t\t\t// stored number is not a zero, override it to zero and store new value\n\t\t\tif ( isNaN( count ) ) {\n\t\t\t\tcount = 0;\n\t\t\t\tthis.setPreviewCount( count );\n\t\t\t}\n\t\t\treturn count;\n\t\t},\n\n\t\t/**\n\t\t * Sets the number of previews that the user has seen.\n\t\t *\n\t\t * @function\n\t\t * @name UserSettings#setPreviewCount\n\t\t * @param {Number} count\n\t\t */\n\t\tsetPreviewCount: function ( count ) {\n\t\t\tstorage.set( PREVIEW_COUNT_KEY, count.toString() );\n\t\t}\n\t};\n}\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/userSettings.js\n// module id = ./src/userSettings.js\n// module chunks = 0","/**\n * @module wait\n */\n\nvar $ = jQuery;\n\n/**\n * Sugar around `window.setTimeout`.\n *\n * @example\n * import wait from './wait';\n *\n * wait( 150 )\n * .then( function () {\n * // Continue processing...\n * } );\n *\n * @param {Number} delay The number of milliseconds to wait\n * @return {jQuery.Promise}\n */\nexport default function wait( delay ) {\n\tvar result = $.Deferred();\n\n\tsetTimeout( function () {\n\t\tresult.resolve();\n\t}, delay );\n\n\treturn result.promise();\n}\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/wait.js\n// module id = ./src/wait.js\n// module chunks = 0"],"sourceRoot":""} |