' )\n\t\t\t\t\t\t.addClass( 'mw-ui-icon mw-ui-icon-element mw-ui-icon-small mw-ui-icon-settings' )\n\t\t\t\t)\n\t\t);\n\t} else {\n\t\t// Change the styling when there is no content in the footer (to prevent empty space)\n\t\t$el.find( '.mwe-popups-container' ).addClass( 'footer-empty' );\n\t}\n\n\tif ( isTracking ) {\n\t\t$el.find( '.mw-parser-output' ).on( 'click', 'a', () => {\n\t\t\tmw.track( LOGGING_SCHEMA, {\n\t\t\t\taction: 'clickedReferencePreviewsContentLink'\n\t\t\t} );\n\t\t} );\n\t}\n\n\t$el.find( '.mwe-popups-scroll' ).on( 'scroll', function ( e ) {\n\t\tconst element = e.target,\n\t\t\t// We are dealing with floating point numbers here when the page is zoomed!\n\t\t\tscrolledToBottom = element.scrollTop >= element.scrollHeight - element.clientHeight - 1;\n\n\t\tif ( isTracking ) {\n\t\t\tif ( !element.isOpenRecorded ) {\n\t\t\t\tmw.track( LOGGING_SCHEMA, {\n\t\t\t\t\taction: 'poppedOpen',\n\t\t\t\t\tscrollbarsPresent: element.scrollHeight > element.clientHeight\n\t\t\t\t} );\n\t\t\t\telement.isOpenRecorded = true;\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\telement.scrollTop > 0 &&\n\t\t\t\t!element.isScrollRecorded\n\t\t\t) {\n\t\t\t\tmw.track( LOGGING_SCHEMA, {\n\t\t\t\t\taction: 'scrolled'\n\t\t\t\t} );\n\t\t\t\telement.isScrollRecorded = true;\n\t\t\t}\n\t\t}\n\n\t\tif ( !scrolledToBottom && element.isScrolling ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst $extract = $( element ).parent(),\n\t\t\thasHorizontalScroll = element.scrollWidth > element.clientWidth,\n\t\t\tscrollbarHeight = element.offsetHeight - element.clientHeight,\n\t\t\thasVerticalScroll = element.scrollHeight > element.clientHeight,\n\t\t\tscrollbarWidth = element.offsetWidth - element.clientWidth;\n\t\t$extract.find( '.mwe-popups-fade' ).css( {\n\t\t\tbottom: hasHorizontalScroll ? `${scrollbarHeight}px` : 0,\n\t\t\tright: hasVerticalScroll ? `${scrollbarWidth}px` : 0\n\t\t} );\n\n\t\telement.isScrolling = !scrolledToBottom;\n\t\t$extract.toggleClass( 'mwe-popups-fade-out', element.isScrolling );\n\t} );\n\n\treturn $el;\n}\n","/**\n * @module pagePreview\n */\n\nimport { renderPopup } from '../popup/popup';\nimport { createNodeFromTemplate } from '../templateUtil';\n\nconst defaultExtractWidth = 215;\nconst templateHTML = `\n\n \n \n \n
\n\t`;\n\n/**\n * @param {ext.popups.PagePreviewModel} model\n * @param {ext.popups.Thumbnail|null} thumbnail\n * @param {boolean} withCSSClipPath\n * @param {string} linkTitle\n * @return {JQuery}\n */\nexport function renderPagePreview(\n\tmodel, thumbnail, withCSSClipPath, linkTitle\n) {\n\tconst $el = renderPopup( model.type, createNodeFromTemplate( templateHTML ) );\n\n\t$el.find( '.mwe-popups-discreet, .mwe-popups-extract' )\n\t\t.attr( 'href', model.url );\n\n\t$el.find( '.mwe-popups-extract' )\n\t\t.attr( 'dir', model.languageDirection )\n\t\t.attr( 'lang', model.languageCode );\n\n\t$el.find( '.mwe-popups-settings-icon' )\n\t\t.attr( 'title', linkTitle );\n\n\tif ( thumbnail ) {\n\t\t$el.find( '.mwe-popups-discreet' ).append( thumbnail.el );\n\t} else {\n\t\t$el.find( '.mwe-popups-discreet' ).remove();\n\t}\n\n\tconst $extract = $el.find( '.mwe-popups-extract' );\n\tif ( model.extract ) {\n\t\t$extract.append( model.extract );\n\t\tconst extractWidth = getExtractWidth( thumbnail );\n\t\tif ( !withCSSClipPath ) {\n\t\t\t$extract.css( 'width', extractWidth );\n\t\t\t$el.find( 'footer' ).css( 'width', extractWidth );\n\t\t}\n\t}\n\n\treturn $el;\n}\n\nexport { defaultExtractWidth }; // for testing\n\n/**\n * Calculates width of extract based on the associated thumbnail\n *\n * @param {ext.popups.Thumbnail|null} thumbnail model\n * @return {string} representing the css width attribute to be\n * used for the extract\n */\nexport function getExtractWidth( thumbnail ) {\n\treturn thumbnail && thumbnail.isNarrow ? `${defaultExtractWidth + thumbnail.offset}px` : '';\n}\n","/**\n * @module renderer\n */\n\nimport wait from '../wait';\nimport pointerMaskSVG from './pointer-mask.svg';\nimport { SIZES, createThumbnail } from './thumbnail';\nimport { renderPreview } from './templates/preview/preview';\nimport { renderReferencePreview } from './templates/referencePreview/referencePreview';\nimport { renderPagePreview } from './templates/pagePreview/pagePreview';\n\nconst landscapePopupWidth = 450,\n\tportraitPopupWidth = 320,\n\tpointerSize = 8, // Height of the pointer.\n\tmaxLinkWidthForCenteredPointer = 28; // Link with roughly < 4 chars.\n\nexport { pointerSize, landscapePopupWidth, portraitPopupWidth }; // for use in storybook\n\n/**\n * @typedef {Object} ext.popups.Measures\n * @property {number} pageX\n * @property {number} pageY\n * @property {number} clientY\n * @property {ClientRectList} clientRects list of rectangles defined by\n * four edges\n * @property {Object} offset\n * @property {number} width\n * @property {number} height\n * @property {number} scrollTop\n * @property {number} windowWidth\n * @property {number} windowHeight\n */\n\n/**\n * Extracted from `mw.popups.createSVGMasks`. This is just an SVG mask to point\n * or \"point\" at the link that's hovered over. The \"pointer\" appears to be cut\n * out of the image itself:\n * _______ link\n * | | _/\\_____ _/\\____ <-- Pointer pointing at link\n * | :-] | + |xxxxxxx = | :-] |\n * |_______| |xxxxxxx |_______|\n * :\n * Thumbnail Pointer Page preview\n * image clip-path bubble w/ pointer\n *\n * SVG masks are used in place of CSS masks for browser support issues (see\n * https://caniuse.com/#feat=css-masks).\n *\n * @private\n * @param {Object} container DOM object to which pointer masks are appended\n * @return {void}\n */\nexport function createPointerMasks( container ) {\n\t$( '