mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/Popups
synced 2024-11-23 15:16:50 +00:00
Reference previews should use Popups registration
* Adds a new webpack entry point for references previews * Reference related code in src/index.js is moved to new file resources/ext.popups.referencePreviews/index.js The changes: * References previews now in its own module ext.popups.referencePreviews * Loaded via getCustomPopupTypes * OWNERS.md files make clear which team owns which part of the code. Bug: T326692 Change-Id: Iea8a5b9221c0b1fd41e40bff2cbe01e42124d53f
This commit is contained in:
parent
31ef381e90
commit
59c6b8e88f
|
@ -152,6 +152,15 @@
|
|||
"resources/ext.popups/index.js"
|
||||
]
|
||||
},
|
||||
"ext.popups.referencePreviews": {
|
||||
"styles": [
|
||||
"resources/ext.popups.referencePreviews/referencePreview.less"
|
||||
],
|
||||
"scripts": [
|
||||
"resources/dist/referencePreviews.js",
|
||||
"resources/ext.popups.referencePreviews/index.js"
|
||||
]
|
||||
},
|
||||
"ext.popups.main": {
|
||||
"scripts": [
|
||||
"resources/dist/index.js"
|
||||
|
|
|
@ -67,9 +67,11 @@ class PopupsHooks implements
|
|||
* @return array
|
||||
*/
|
||||
public static function getCustomPopupTypes(): array {
|
||||
return ExtensionRegistry::getInstance()->getAttribute(
|
||||
return array_merge( ExtensionRegistry::getInstance()->getAttribute(
|
||||
'PopupsPluginModules'
|
||||
);
|
||||
), [
|
||||
'ext.popups.referencePreviews'
|
||||
] );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -71,7 +71,11 @@
|
|||
"bundlesize": [
|
||||
{
|
||||
"path": "resources/dist/index.js",
|
||||
"maxSize": "15.1kB"
|
||||
"maxSize": "13.5kB"
|
||||
},
|
||||
{
|
||||
"path": "resources/dist/referencePreviews.js",
|
||||
"maxSize": "2.7kB"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
BIN
resources/dist/index.js
vendored
BIN
resources/dist/index.js
vendored
Binary file not shown.
BIN
resources/dist/index.js.map.json
vendored
BIN
resources/dist/index.js.map.json
vendored
Binary file not shown.
BIN
resources/dist/referencePreviews.js
vendored
Normal file
BIN
resources/dist/referencePreviews.js
vendored
Normal file
Binary file not shown.
BIN
resources/dist/referencePreviews.js.map.json
vendored
Normal file
BIN
resources/dist/referencePreviews.js.map.json
vendored
Normal file
Binary file not shown.
1
resources/ext.popups.referencePreviews/index.js
Normal file
1
resources/ext.popups.referencePreviews/index.js
Normal file
|
@ -0,0 +1 @@
|
|||
module.exports = window.refPreviews;
|
|
@ -1,11 +1,36 @@
|
|||
@import 'mediawiki.skin.variables.less';
|
||||
@import '../../src/ui/variables.less';
|
||||
|
||||
// Don't do any event bubbling on childs like <a><span>[</span>2]</a>, see T214693
|
||||
.popups-icon--reference-generic {
|
||||
.cdx-mixin-css-icon( @cdx-icon-reference );
|
||||
}
|
||||
|
||||
.popups-icon--reference-book {
|
||||
.cdx-mixin-css-icon( @cdx-icon-book );
|
||||
}
|
||||
|
||||
.popups-icon--reference-journal {
|
||||
.cdx-mixin-css-icon( @cdx-icon-journal );
|
||||
}
|
||||
|
||||
.popups-icon--reference-news {
|
||||
.cdx-mixin-css-icon( @cdx-icon-newspaper );
|
||||
}
|
||||
|
||||
.popups-icon--reference-web {
|
||||
.cdx-mixin-css-icon( @cdx-icon-browser );
|
||||
}
|
||||
|
||||
.popups-icon--preview-disambiguation {
|
||||
.cdx-mixin-css-icon( @cdx-icon-articles );
|
||||
}
|
||||
|
||||
// Don't do any event bubbling on childs like <a><span>[</span>2]</a>
|
||||
// see https://phabricator.wikimedia.org/T214693
|
||||
#mw-content-text .reference a[ href*='#' ] * {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.mwe-popups.mwe-popups-type-reference {
|
||||
.mwe-popups.mwe-popups-type-reference .mwe-popups-container {
|
||||
.mwe-popups-title .popups-icon--reference-note {
|
||||
// There is currently no "reference-note" icon specified in extension.json
|
||||
display: none;
|
||||
|
@ -14,13 +39,12 @@
|
|||
.mwe-popups-extract {
|
||||
margin-right: 0;
|
||||
max-height: inherit;
|
||||
|
||||
.mwe-popups-scroll {
|
||||
// This is how the `margin-bottom: 47px` in popup.less is calculated
|
||||
@marginBottom: 2 * @lineHeight + 7px;
|
||||
// Same as the --pointer-height in popup.less
|
||||
// This is how the @previewFooterHeight in popup.less is calculated
|
||||
@marginBottom: @popupPadding + 34px;
|
||||
// Same as @previewPointerHeight in popup.less
|
||||
@pointerHeight: 8px;
|
||||
max-height: 403px - @popupPadding - @marginBottom + @pointerHeight;
|
||||
max-height: 401px - @popupPadding - @marginBottom + @pointerHeight;
|
||||
overflow: auto;
|
||||
padding-right: @popupPadding;
|
||||
}
|
||||
|
@ -49,7 +73,6 @@
|
|||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.mwe-collapsible-placeholder {
|
||||
font-weight: bold;
|
||||
margin: 1em 0;
|
1
src/OWNERS.md
Normal file
1
src/OWNERS.md
Normal file
|
@ -0,0 +1 @@
|
|||
Code in this folder and subfolders is maintained by the Web Team unless stated.
|
|
@ -20,11 +20,6 @@ export const FETCH_COMPLETE_TARGET_DELAY = 350 + FETCH_START_DELAY; // ms.
|
|||
export const PREVIEW_SEEN_DURATION = 1000; // ms
|
||||
export const ABANDON_END_DELAY = 300;
|
||||
|
||||
//
|
||||
// Reference previews specific config
|
||||
//
|
||||
export const FETCH_DELAY_REFERENCE_TYPE = 150; // ms.
|
||||
|
||||
export default {
|
||||
BRACKETED_DEVICE_PIXEL_RATIO: bpr,
|
||||
// See https://phabricator.wikimedia.org/T272169: requesting a larger thumbnail to avoid bluriness
|
||||
|
|
1
src/ext.popups.referencePreviews/OWNERS.md
Normal file
1
src/ext.popups.referencePreviews/OWNERS.md
Normal file
|
@ -0,0 +1 @@
|
|||
Code in this folder and subfolders is maintained by WMDE.
|
2
src/ext.popups.referencePreviews/constants.js
Normal file
2
src/ext.popups.referencePreviews/constants.js
Normal file
|
@ -0,0 +1,2 @@
|
|||
export const TYPE_REFERENCE = 'reference';
|
||||
export const FETCH_DELAY_REFERENCE_TYPE = 150; // ms.
|
|
@ -2,8 +2,8 @@
|
|||
* @module gateway/reference
|
||||
*/
|
||||
|
||||
import { previewTypes } from '../preview/model';
|
||||
import { abortablePromise } from './index.js';
|
||||
import { TYPE_REFERENCE } from './constants.js';
|
||||
import { abortablePromise } from '../gateway/index.js';
|
||||
|
||||
/**
|
||||
* @return {Gateway}
|
||||
|
@ -77,7 +77,7 @@ export default function createReferenceGateway() {
|
|||
const model = {
|
||||
url: `#${ id }`,
|
||||
extract: referenceNode.innerHTML,
|
||||
type: previewTypes.TYPE_REFERENCE,
|
||||
type: TYPE_REFERENCE,
|
||||
referenceType: scrapeReferenceType( referenceNode ),
|
||||
// Note: Even the top-most HTMLHtmlElement is guaranteed to have a parent.
|
||||
sourceElementId: el.parentNode.id
|
|
@ -1,9 +1,9 @@
|
|||
/**
|
||||
* @module referencePreview
|
||||
*/
|
||||
import { isTrackingEnabled, LOGGING_SCHEMA } from '../../../instrumentation/referencePreviews';
|
||||
import { renderPopup } from '../popup/popup';
|
||||
import { createNodeFromTemplate, escapeHTML } from '../templateUtil';
|
||||
import { isTrackingEnabled, LOGGING_SCHEMA } from './referencePreviews';
|
||||
import { renderPopup } from '../ui/templates/popup/popup';
|
||||
import { createNodeFromTemplate, escapeHTML } from '../ui/templates/templateUtil';
|
||||
|
||||
const templateHTML = `
|
||||
<div class="mwe-popups-container">
|
||||
|
@ -39,7 +39,7 @@ const replaceWith = ( node, htmlOrOtherNode ) => {
|
|||
* @param {ext.popups.ReferencePreviewModel} model
|
||||
* @return {jQuery}
|
||||
*/
|
||||
export function renderReferencePreview(
|
||||
function renderReferencePreview(
|
||||
model
|
||||
) {
|
||||
const type = model.referenceType || 'generic';
|
||||
|
@ -170,3 +170,15 @@ export function renderReferencePreview(
|
|||
|
||||
return el;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ext.popups.ReferencePreviewModel} model
|
||||
* @return {ext.popups.Preview}
|
||||
*/
|
||||
export default function createReferencePreview( model ) {
|
||||
return {
|
||||
el: renderReferencePreview( model ),
|
||||
hasThumbnail: false,
|
||||
isTall: false
|
||||
};
|
||||
}
|
23
src/ext.popups.referencePreviews/index.js
Normal file
23
src/ext.popups.referencePreviews/index.js
Normal file
|
@ -0,0 +1,23 @@
|
|||
import isReferencePreviewsEnabled from './isReferencePreviewsEnabled';
|
||||
import { initReferencePreviewsInstrumentation } from './referencePreviews';
|
||||
import createReferenceGateway from './createReferenceGateway';
|
||||
import renderFn from './createReferencePreview';
|
||||
import { TYPE_REFERENCE, FETCH_DELAY_REFERENCE_TYPE } from './constants';
|
||||
import createUserSettings from '../userSettings';
|
||||
import setUserConfigFlags from './setUserConfigFlags';
|
||||
|
||||
setUserConfigFlags( mw.config );
|
||||
const userSettings = createUserSettings( mw.storage );
|
||||
const referencePreviewsState = isReferencePreviewsEnabled( mw.user, userSettings, mw.config );
|
||||
const gateway = createReferenceGateway();
|
||||
|
||||
window.refPreviews = referencePreviewsState !== null ? {
|
||||
type: TYPE_REFERENCE,
|
||||
selector: '#mw-content-text .reference a[ href*="#" ]',
|
||||
delay: FETCH_DELAY_REFERENCE_TYPE,
|
||||
gateway,
|
||||
renderFn,
|
||||
init: () => {
|
||||
initReferencePreviewsInstrumentation();
|
||||
}
|
||||
} : null;
|
|
@ -1,9 +1,9 @@
|
|||
import { previewTypes } from './preview/model';
|
||||
import { TYPE_REFERENCE } from './constants.js';
|
||||
|
||||
/**
|
||||
* @module isReferencePreviewsEnabled
|
||||
*/
|
||||
const canSaveToUserPreferences = require( './canSaveToUserPreferences.js' );
|
||||
const canSaveToUserPreferences = require( '../canSaveToUserPreferences.js' );
|
||||
|
||||
/**
|
||||
* Given the global state of the application, creates a function that gets
|
||||
|
@ -34,9 +34,9 @@ export default function isReferencePreviewsEnabled( user, userSettings, config )
|
|||
// For anonymous users, the code loads always, but the feature can be toggled at run-time via
|
||||
// local storage.
|
||||
if ( !canSaveToUserPreferences( user ) ) {
|
||||
return userSettings.isPreviewTypeEnabled( previewTypes.TYPE_REFERENCE );
|
||||
return userSettings.isPreviewTypeEnabled( TYPE_REFERENCE );
|
||||
}
|
||||
|
||||
// Registered users never can enable popup types at run-time.
|
||||
return mw.user.options.get( 'popups-reference-previews' ) === '1' ? true : null;
|
||||
return user.options.get( 'popups-reference-previews' ) === '1' ? true : null;
|
||||
}
|
29
src/ext.popups.referencePreviews/setUserConfigFlags.js
Normal file
29
src/ext.popups.referencePreviews/setUserConfigFlags.js
Normal file
|
@ -0,0 +1,29 @@
|
|||
/**
|
||||
* @module setUserConfigFlags
|
||||
*/
|
||||
|
||||
/**
|
||||
* Same as in includes/PopupsContext.php
|
||||
*/
|
||||
const REF_TOOLTIPS_ENABLED = 2,
|
||||
REFERENCE_PREVIEWS_ENABLED = 4;
|
||||
|
||||
/**
|
||||
* Decodes the bitmask that represents preferences to the related config options.
|
||||
*
|
||||
* @param {mw.Map} config
|
||||
*/
|
||||
export default function setUserConfigFlags( config ) {
|
||||
const popupsFlags = parseInt( config.get( 'wgPopupsFlags' ), 10 );
|
||||
|
||||
/* eslint-disable no-bitwise */
|
||||
config.set(
|
||||
'wgPopupsConflictsWithRefTooltipsGadget',
|
||||
!!( popupsFlags & REF_TOOLTIPS_ENABLED )
|
||||
);
|
||||
config.set(
|
||||
'wgPopupsReferencePreviews',
|
||||
!!( popupsFlags & REFERENCE_PREVIEWS_ENABLED )
|
||||
);
|
||||
/* eslint-enable no-bitwise */
|
||||
}
|
24
src/index.js
24
src/index.js
|
@ -6,7 +6,6 @@ import * as Redux from 'redux';
|
|||
import * as ReduxThunk from 'redux-thunk';
|
||||
|
||||
import createPagePreviewGateway from './gateway/page';
|
||||
import createReferenceGateway from './gateway/reference';
|
||||
import createUserSettings from './userSettings';
|
||||
import createPreviewBehavior from './previewBehavior';
|
||||
import createSettingsDialogRenderer from './ui/settingsDialogRenderer';
|
||||
|
@ -14,8 +13,7 @@ import registerChangeListener from './changeListener';
|
|||
import createIsPagePreviewsEnabled from './isPagePreviewsEnabled';
|
||||
import { fromElement as titleFromElement } from './title';
|
||||
import { init as rendererInit, registerPreviewUI, createPagePreview,
|
||||
createDisambiguationPreview,
|
||||
createReferencePreview
|
||||
createDisambiguationPreview
|
||||
} from './ui/renderer';
|
||||
import createExperiments from './experiments';
|
||||
import { isEnabled as isStatsvEnabled } from './instrumentation/statsv';
|
||||
|
@ -26,11 +24,9 @@ import createMediaWikiPopupsObject from './integrations/mwpopups';
|
|||
import { previewTypes, getPreviewType,
|
||||
registerModel,
|
||||
isAnythingEligible, findNearestEligibleTarget } from './preview/model';
|
||||
import isReferencePreviewsEnabled from './isReferencePreviewsEnabled';
|
||||
import setUserConfigFlags from './setUserConfigFlags';
|
||||
import { registerGatewayForPreviewType, getGatewayForPreviewType } from './gateway';
|
||||
import { initReferencePreviewsInstrumentation } from './instrumentation/referencePreviews';
|
||||
import { FETCH_START_DELAY, FETCH_COMPLETE_TARGET_DELAY, FETCH_DELAY_REFERENCE_TYPE } from './constants';
|
||||
import { FETCH_START_DELAY, FETCH_COMPLETE_TARGET_DELAY } from './constants';
|
||||
|
||||
const EXCLUDED_LINK_SELECTORS = [
|
||||
'.extiw',
|
||||
|
@ -188,9 +184,7 @@ function handleDOMEventIfEligible( handler ) {
|
|||
// So-called "services".
|
||||
generateToken = mw.user.generateRandomSessionId,
|
||||
pagePreviewGateway = createPagePreviewGateway( mw.config ),
|
||||
referenceGateway = createReferenceGateway(),
|
||||
userSettings = createUserSettings( mw.storage ),
|
||||
referencePreviewsState = isReferencePreviewsEnabled( mw.user, userSettings, mw.config ),
|
||||
settingsDialog = createSettingsDialogRenderer(),
|
||||
experiments = createExperiments( mw.experiments ),
|
||||
statsvTracker = getStatsvTracker( mw.user, mw.config, experiments ),
|
||||
|
@ -258,19 +252,7 @@ function handleDOMEventIfEligible( handler ) {
|
|||
]
|
||||
} );
|
||||
}
|
||||
if ( referencePreviewsState !== null ) {
|
||||
// Register the reference preview type
|
||||
mw.popups.register( {
|
||||
type: previewTypes.TYPE_REFERENCE,
|
||||
selector: '#mw-content-text .reference a[ href*="#" ]',
|
||||
delay: FETCH_DELAY_REFERENCE_TYPE,
|
||||
gateway: referenceGateway,
|
||||
renderFn: createReferencePreview,
|
||||
init: () => {
|
||||
initReferencePreviewsInstrumentation();
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
if ( !isAnythingEligible() ) {
|
||||
mw.log.warn( 'ext.popups was loaded but everything is disabled' );
|
||||
return;
|
||||
|
|
|
@ -18,9 +18,7 @@ const previewTypes = {
|
|||
/** Standard page preview with or without thumbnail */
|
||||
TYPE_PAGE: 'page',
|
||||
/** Disambiguation page preview */
|
||||
TYPE_DISAMBIGUATION: 'disambiguation',
|
||||
/** Reference preview */
|
||||
TYPE_REFERENCE: 'reference'
|
||||
TYPE_DISAMBIGUATION: 'disambiguation'
|
||||
};
|
||||
|
||||
export { previewTypes };
|
||||
|
|
|
@ -5,9 +5,7 @@
|
|||
/**
|
||||
* Same as in includes/PopupsContext.php
|
||||
*/
|
||||
const NAV_POPUPS_ENABLED = 1,
|
||||
REF_TOOLTIPS_ENABLED = 2,
|
||||
REFERENCE_PREVIEWS_ENABLED = 4;
|
||||
const NAV_POPUPS_ENABLED = 1;
|
||||
|
||||
/**
|
||||
* Decodes the bitmask that represents preferences to the related config options.
|
||||
|
@ -22,13 +20,5 @@ export default function setUserConfigFlags( config ) {
|
|||
'wgPopupsConflictsWithNavPopupGadget',
|
||||
!!( popupsFlags & NAV_POPUPS_ENABLED )
|
||||
);
|
||||
config.set(
|
||||
'wgPopupsConflictsWithRefTooltipsGadget',
|
||||
!!( popupsFlags & REF_TOOLTIPS_ENABLED )
|
||||
);
|
||||
config.set(
|
||||
'wgPopupsReferencePreviews',
|
||||
!!( popupsFlags & REFERENCE_PREVIEWS_ENABLED )
|
||||
);
|
||||
/* eslint-enable no-bitwise */
|
||||
}
|
||||
|
|
|
@ -9,27 +9,3 @@
|
|||
.popups-icon--close {
|
||||
.cdx-mixin-css-icon( @cdx-icon-close );
|
||||
}
|
||||
|
||||
.popups-icon--reference-generic {
|
||||
.cdx-mixin-css-icon( @cdx-icon-reference );
|
||||
}
|
||||
|
||||
.popups-icon--reference-book {
|
||||
.cdx-mixin-css-icon( @cdx-icon-book );
|
||||
}
|
||||
|
||||
.popups-icon--reference-journal {
|
||||
.cdx-mixin-css-icon( @cdx-icon-journal );
|
||||
}
|
||||
|
||||
.popups-icon--reference-news {
|
||||
.cdx-mixin-css-icon( @cdx-icon-newspaper );
|
||||
}
|
||||
|
||||
.popups-icon--reference-web {
|
||||
.cdx-mixin-css-icon( @cdx-icon-browser );
|
||||
}
|
||||
|
||||
.popups-icon--preview-disambiguation {
|
||||
.cdx-mixin-css-icon( @cdx-icon-articles );
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
@import 'templates/settingsDialog/settingsDialog.less';
|
||||
@import 'templates/popup/popup.less';
|
||||
@import 'templates/preview/preview.less';
|
||||
@import 'templates/referencePreview/referencePreview.less';
|
||||
@import 'settingsDialogRenderer.less';
|
||||
|
||||
#mwe-popups-svg {
|
||||
|
|
|
@ -6,7 +6,6 @@ import wait from '../wait';
|
|||
import pointerMaskSVG from './pointer-mask.svg';
|
||||
import { SIZES, createThumbnail } from './thumbnail';
|
||||
import { renderPreview } from './templates/preview/preview';
|
||||
import { renderReferencePreview } from './templates/referencePreview/referencePreview';
|
||||
import { renderPagePreview } from './templates/pagePreview/pagePreview';
|
||||
|
||||
const landscapePopupWidth = 450,
|
||||
|
@ -244,18 +243,6 @@ export function createDisambiguationPreview( model ) {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ext.popups.ReferencePreviewModel} model
|
||||
* @return {ext.popups.Preview}
|
||||
*/
|
||||
export function createReferencePreview( model ) {
|
||||
return {
|
||||
el: renderReferencePreview( model ),
|
||||
hasThumbnail: false,
|
||||
isTall: false
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the preview.
|
||||
*
|
||||
|
|
1
tests/OWNERS.md
Normal file
1
tests/OWNERS.md
Normal file
|
@ -0,0 +1 @@
|
|||
Code in this folder and subfolders is maintained by the Web Team unless stated.
|
1
tests/node-qunit/ext.popups.referencePreviews/OWNERS.md
Normal file
1
tests/node-qunit/ext.popups.referencePreviews/OWNERS.md
Normal file
|
@ -0,0 +1 @@
|
|||
Code in this folder and subfolders is maintained by WMDE.
|
|
@ -1,7 +1,7 @@
|
|||
import { createStubTitle } from '../stubs';
|
||||
import createReferenceGateway from '../../../src/gateway/reference';
|
||||
import createReferenceGateway from '../../../src/ext.popups.referencePreviews/createReferenceGateway';
|
||||
|
||||
QUnit.module( 'ext.popups/gateway/reference', {
|
||||
QUnit.module( 'ext.popups.referencePreviews/createReferenceGateway', {
|
||||
beforeEach() {
|
||||
global.CSS = {
|
||||
escape: ( str ) => $.escapeSelector( str )
|
|
@ -1,5 +1,5 @@
|
|||
import * as stubs from './stubs';
|
||||
import isReferencePreviewsEnabled from '../../src/isReferencePreviewsEnabled';
|
||||
import * as stubs from '../stubs';
|
||||
import isReferencePreviewsEnabled from '../../../src/ext.popups.referencePreviews/isReferencePreviewsEnabled';
|
||||
|
||||
function createStubUserSettings( expectEnabled ) {
|
||||
return {
|
||||
|
@ -9,14 +9,9 @@ function createStubUserSettings( expectEnabled ) {
|
|||
};
|
||||
}
|
||||
|
||||
QUnit.module( 'ext.popups#isReferencePreviewsEnabled', {
|
||||
beforeEach() {
|
||||
mw.user = { options: { get: () => '1' } };
|
||||
},
|
||||
afterEach() {
|
||||
mw.user = null;
|
||||
}
|
||||
} );
|
||||
const options = { get: () => '1' };
|
||||
|
||||
QUnit.module( 'ext.popups.referencePreviews#isReferencePreviewsEnabled' );
|
||||
|
||||
QUnit.test( 'all relevant combinations of flags', ( assert ) => {
|
||||
[
|
||||
|
@ -125,7 +120,10 @@ QUnit.test( 'all relevant combinations of flags', ( assert ) => {
|
|||
].forEach( ( data ) => {
|
||||
const user = {
|
||||
isNamed: () => !data.isAnon && !data.isIPMasked,
|
||||
isAnon: () => data.isAnon
|
||||
isAnon: () => data.isAnon,
|
||||
options: {
|
||||
get: () => {}
|
||||
}
|
||||
},
|
||||
userSettings = {
|
||||
isPreviewTypeEnabled: () => data.isAnon ?
|
||||
|
@ -137,9 +135,9 @@ QUnit.test( 'all relevant combinations of flags', ( assert ) => {
|
|||
};
|
||||
|
||||
if ( data.isAnon ) {
|
||||
mw.user.options.get = () => assert.true( false, 'not expected to be called' );
|
||||
user.options.get = () => assert.true( false, 'not expected to be called' );
|
||||
} else {
|
||||
mw.user.options.get = () => data.enabledByRegistered ? '1' : '0';
|
||||
user.options.get = () => data.enabledByRegistered ? '1' : '0';
|
||||
}
|
||||
|
||||
assert.strictEqual(
|
||||
|
@ -151,7 +149,7 @@ QUnit.test( 'all relevant combinations of flags', ( assert ) => {
|
|||
} );
|
||||
|
||||
QUnit.test( 'it should display reference previews when conditions are fulfilled', ( assert ) => {
|
||||
const user = stubs.createStubUser( false ),
|
||||
const user = stubs.createStubUser( false, options ),
|
||||
userSettings = createStubUserSettings( false ),
|
||||
config = new Map();
|
||||
|
126
tests/node-qunit/ext.popups.referencePreviews/renderer.test.js
Normal file
126
tests/node-qunit/ext.popups.referencePreviews/renderer.test.js
Normal file
|
@ -0,0 +1,126 @@
|
|||
import * as renderer from '../../../src/ui/renderer';
|
||||
import * as constants from '../../../src/constants';
|
||||
import { previewTypes } from '../../../src/preview/model';
|
||||
import createReferencePreview from '../../../src/ext.popups.referencePreviews/createReferencePreview';
|
||||
|
||||
QUnit.module( 'ext.popups.referencePreviews#renderer', {
|
||||
beforeEach() {
|
||||
this.sandbox.stub( constants.default, 'BRACKETED_DEVICE_PIXEL_RATIO' ).value( 1 );
|
||||
|
||||
mw.msg = ( key ) => `<${ key }>`;
|
||||
mw.message = ( key ) => {
|
||||
return { exists: () => !key.endsWith( 'generic' ), text: () => `<${ key }>` };
|
||||
};
|
||||
|
||||
mw.html = {
|
||||
escape: ( str ) => str && str.replace( /'/g, ''' ).replace( /</g, '<' )
|
||||
};
|
||||
|
||||
mw.track = () => {};
|
||||
|
||||
global.navigator = {
|
||||
sendBeacon() {}
|
||||
};
|
||||
|
||||
// Some tests below stub this function. Keep a copy so it can be restored.
|
||||
this.getElementById = document.getElementById;
|
||||
},
|
||||
afterEach() {
|
||||
// Restore getElementsById to its original state.
|
||||
document.getElementById = this.getElementById;
|
||||
mw.msg = null;
|
||||
mw.message = null;
|
||||
mw.html = null;
|
||||
renderer.test.reset();
|
||||
}
|
||||
} );
|
||||
|
||||
QUnit.test( 'createReferencePreview(model)', ( assert ) => {
|
||||
renderer.registerPreviewUI(
|
||||
previewTypes.TYPE_REFERENCE,
|
||||
createReferencePreview
|
||||
);
|
||||
const model = {
|
||||
url: '#custom_id',
|
||||
extract: 'Custom <i>extract</i> with an <a href="/wiki/Internal">internal</a> and an <a href="//wikipedia.de" class="external">external</a> link',
|
||||
type: previewTypes.TYPE_REFERENCE,
|
||||
referenceType: 'web'
|
||||
},
|
||||
preview = renderer.createPreviewWithType( model );
|
||||
|
||||
assert.strictEqual( preview.hasThumbnail, false );
|
||||
assert.strictEqual( preview.isTall, false );
|
||||
|
||||
assert.strictEqual(
|
||||
$( preview.el ).find( '.mwe-popups-title' ).text().trim(),
|
||||
'<popups-refpreview-web>'
|
||||
);
|
||||
assert.strictEqual(
|
||||
$( preview.el ).find( '.mw-parser-output' ).text().trim(),
|
||||
'Custom extract with an internal and an external link'
|
||||
);
|
||||
assert.strictEqual(
|
||||
$( preview.el ).find( 'a[target="_blank"]' ).length,
|
||||
1,
|
||||
'only external links open in new tabs'
|
||||
);
|
||||
} );
|
||||
|
||||
QUnit.test( 'createReferencePreview default title', ( assert ) => {
|
||||
renderer.registerPreviewUI(
|
||||
previewTypes.TYPE_REFERENCE,
|
||||
createReferencePreview
|
||||
);
|
||||
const model = {
|
||||
url: '',
|
||||
extract: '',
|
||||
type: previewTypes.TYPE_REFERENCE
|
||||
},
|
||||
preview = renderer.createPreviewWithType( model );
|
||||
|
||||
assert.strictEqual(
|
||||
$( preview.el ).find( '.mwe-popups-title' ).text().trim(),
|
||||
'<popups-refpreview-reference>'
|
||||
);
|
||||
} );
|
||||
|
||||
QUnit.test( 'createReferencePreview updates fade-out effect on scroll', ( assert ) => {
|
||||
renderer.registerPreviewUI(
|
||||
previewTypes.TYPE_REFERENCE,
|
||||
createReferencePreview
|
||||
);
|
||||
const model = {
|
||||
url: '',
|
||||
extract: '',
|
||||
type: previewTypes.TYPE_REFERENCE
|
||||
},
|
||||
preview = renderer.createPreviewWithType( model ),
|
||||
$extract = $( preview.el ).find( '.mwe-popups-extract' );
|
||||
|
||||
$extract.children()[ 0 ].dispatchEvent( new Event( 'scroll' ) );
|
||||
|
||||
assert.false( $extract.children()[ 0 ].isScrolling );
|
||||
assert.false( $extract.hasClass( 'mwe-popups-fade-out' ) );
|
||||
} );
|
||||
|
||||
QUnit.test( 'createReferencePreview collapsible/sortable handling', ( assert ) => {
|
||||
renderer.registerPreviewUI(
|
||||
previewTypes.TYPE_REFERENCE,
|
||||
createReferencePreview
|
||||
);
|
||||
const model = {
|
||||
url: '',
|
||||
extract: '<table class="mw-collapsible"></table>' +
|
||||
'<table class="sortable"><th class="headerSort" tabindex="1" title="Click here"></th></table>',
|
||||
type: previewTypes.TYPE_REFERENCE
|
||||
},
|
||||
preview = renderer.createPreviewWithType( model );
|
||||
|
||||
assert.strictEqual( $( preview.el ).find( '.mw-collapsible, .sortable, .headerSort' ).length, 0 );
|
||||
assert.strictEqual( $( preview.el ).find( 'th' ).attr( 'tabindex' ), undefined );
|
||||
assert.strictEqual( $( preview.el ).find( 'th' ).attr( 'title' ), undefined );
|
||||
assert.strictEqual(
|
||||
$( preview.el ).find( '.mwe-collapsible-placeholder' ).text(),
|
||||
'<popups-refpreview-collapsible-placeholder>'
|
||||
);
|
||||
} );
|
|
@ -0,0 +1,51 @@
|
|||
import setUserConfigFlags from '../../../src/ext.popups.referencePreviews/setUserConfigFlags';
|
||||
|
||||
QUnit.module( 'ext.popups.referencePreviews#setUserConfigFlags' );
|
||||
|
||||
QUnit.test( 'reference preview config settings are successfully set from bitmask', ( assert ) => {
|
||||
const config = new Map();
|
||||
|
||||
config.set( 'wgPopupsFlags', '7' );
|
||||
setUserConfigFlags( config );
|
||||
|
||||
assert.deepEqual(
|
||||
[
|
||||
config.get( 'wgPopupsConflictsWithRefTooltipsGadget' ),
|
||||
config.get( 'wgPopupsReferencePreviews' )
|
||||
],
|
||||
[ true, true ]
|
||||
);
|
||||
|
||||
config.set( 'wgPopupsFlags', '2' );
|
||||
setUserConfigFlags( config );
|
||||
|
||||
assert.deepEqual(
|
||||
[
|
||||
config.get( 'wgPopupsConflictsWithRefTooltipsGadget' ),
|
||||
config.get( 'wgPopupsReferencePreviews' )
|
||||
],
|
||||
[ true, false ]
|
||||
);
|
||||
|
||||
config.set( 'wgPopupsFlags', '5' );
|
||||
setUserConfigFlags( config );
|
||||
|
||||
assert.deepEqual(
|
||||
[
|
||||
config.get( 'wgPopupsConflictsWithRefTooltipsGadget' ),
|
||||
config.get( 'wgPopupsReferencePreviews' )
|
||||
],
|
||||
[ false, true ]
|
||||
);
|
||||
|
||||
config.set( 'wgPopupsFlags', '0' );
|
||||
setUserConfigFlags( config );
|
||||
|
||||
assert.deepEqual(
|
||||
[
|
||||
config.get( 'wgPopupsConflictsWithRefTooltipsGadget' ),
|
||||
config.get( 'wgPopupsReferencePreviews' )
|
||||
],
|
||||
[ false, false ]
|
||||
);
|
||||
} );
|
|
@ -10,11 +10,9 @@ QUnit.test( 'config settings are successfully set from bitmask', ( assert ) => {
|
|||
|
||||
assert.deepEqual(
|
||||
[
|
||||
config.get( 'wgPopupsConflictsWithNavPopupGadget' ),
|
||||
config.get( 'wgPopupsConflictsWithRefTooltipsGadget' ),
|
||||
config.get( 'wgPopupsReferencePreviews' )
|
||||
config.get( 'wgPopupsConflictsWithNavPopupGadget' )
|
||||
],
|
||||
[ true, true, true ]
|
||||
[ true ]
|
||||
);
|
||||
|
||||
config.set( 'wgPopupsFlags', '2' );
|
||||
|
@ -22,11 +20,9 @@ QUnit.test( 'config settings are successfully set from bitmask', ( assert ) => {
|
|||
|
||||
assert.deepEqual(
|
||||
[
|
||||
config.get( 'wgPopupsConflictsWithNavPopupGadget' ),
|
||||
config.get( 'wgPopupsConflictsWithRefTooltipsGadget' ),
|
||||
config.get( 'wgPopupsReferencePreviews' )
|
||||
config.get( 'wgPopupsConflictsWithNavPopupGadget' )
|
||||
],
|
||||
[ false, true, false ]
|
||||
[ false ]
|
||||
);
|
||||
|
||||
config.set( 'wgPopupsFlags', '5' );
|
||||
|
@ -34,11 +30,9 @@ QUnit.test( 'config settings are successfully set from bitmask', ( assert ) => {
|
|||
|
||||
assert.deepEqual(
|
||||
[
|
||||
config.get( 'wgPopupsConflictsWithNavPopupGadget' ),
|
||||
config.get( 'wgPopupsConflictsWithRefTooltipsGadget' ),
|
||||
config.get( 'wgPopupsReferencePreviews' )
|
||||
config.get( 'wgPopupsConflictsWithNavPopupGadget' )
|
||||
],
|
||||
[ true, false, true ]
|
||||
[ true ]
|
||||
);
|
||||
|
||||
config.set( 'wgPopupsFlags', '0' );
|
||||
|
@ -46,10 +40,8 @@ QUnit.test( 'config settings are successfully set from bitmask', ( assert ) => {
|
|||
|
||||
assert.deepEqual(
|
||||
[
|
||||
config.get( 'wgPopupsConflictsWithNavPopupGadget' ),
|
||||
config.get( 'wgPopupsConflictsWithRefTooltipsGadget' ),
|
||||
config.get( 'wgPopupsReferencePreviews' )
|
||||
config.get( 'wgPopupsConflictsWithNavPopupGadget' )
|
||||
],
|
||||
[ false, false, false ]
|
||||
[ false ]
|
||||
);
|
||||
} );
|
||||
|
|
|
@ -3,9 +3,10 @@
|
|||
* instance.
|
||||
*
|
||||
* @param {boolean} isAnon The return value of the `#isAnon`.
|
||||
* @param {Object|mw.Map} [options]
|
||||
* @return {Object}
|
||||
*/
|
||||
export function createStubUser( isAnon ) {
|
||||
export function createStubUser( isAnon, options ) {
|
||||
return {
|
||||
getPageviewToken() {
|
||||
return '9876543210';
|
||||
|
@ -21,7 +22,8 @@ export function createStubUser( isAnon ) {
|
|||
},
|
||||
sessionId() {
|
||||
return '0123456789';
|
||||
}
|
||||
},
|
||||
options
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -321,96 +321,6 @@ QUnit.test( 'createDisambiguationPreview(model)', ( assert ) => {
|
|||
);
|
||||
} );
|
||||
|
||||
QUnit.test( 'createReferencePreview(model)', ( assert ) => {
|
||||
renderer.registerPreviewUI(
|
||||
previewTypes.TYPE_REFERENCE,
|
||||
renderer.createReferencePreview
|
||||
);
|
||||
const model = {
|
||||
url: '#custom_id',
|
||||
extract: 'Custom <i>extract</i> with an <a href="/wiki/Internal">internal</a> and an <a href="//wikipedia.de" class="external">external</a> link',
|
||||
type: previewTypes.TYPE_REFERENCE,
|
||||
referenceType: 'web'
|
||||
},
|
||||
preview = renderer.createPreviewWithType( model );
|
||||
|
||||
assert.strictEqual( preview.hasThumbnail, false );
|
||||
assert.strictEqual( preview.isTall, false );
|
||||
|
||||
assert.strictEqual(
|
||||
$( preview.el ).find( '.mwe-popups-title' ).text().trim(),
|
||||
'<popups-refpreview-web>'
|
||||
);
|
||||
assert.strictEqual(
|
||||
$( preview.el ).find( '.mw-parser-output' ).text().trim(),
|
||||
'Custom extract with an internal and an external link'
|
||||
);
|
||||
assert.strictEqual(
|
||||
$( preview.el ).find( 'a[target="_blank"]' ).length,
|
||||
1,
|
||||
'only external links open in new tabs'
|
||||
);
|
||||
} );
|
||||
|
||||
QUnit.test( 'createReferencePreview collapsible/sortable handling', ( assert ) => {
|
||||
renderer.registerPreviewUI(
|
||||
previewTypes.TYPE_REFERENCE,
|
||||
renderer.createReferencePreview
|
||||
);
|
||||
const model = {
|
||||
url: '',
|
||||
extract: '<table class="mw-collapsible"></table>' +
|
||||
'<table class="sortable"><th class="headerSort" tabindex="1" title="Click here"></th></table>',
|
||||
type: previewTypes.TYPE_REFERENCE
|
||||
},
|
||||
preview = renderer.createPreviewWithType( model );
|
||||
|
||||
assert.strictEqual( $( preview.el ).find( '.mw-collapsible, .sortable, .headerSort' ).length, 0 );
|
||||
assert.strictEqual( $( preview.el ).find( 'th' ).attr( 'tabindex' ), undefined );
|
||||
assert.strictEqual( $( preview.el ).find( 'th' ).attr( 'title' ), undefined );
|
||||
assert.strictEqual(
|
||||
$( preview.el ).find( '.mwe-collapsible-placeholder' ).text(),
|
||||
'<popups-refpreview-collapsible-placeholder>'
|
||||
);
|
||||
} );
|
||||
|
||||
QUnit.test( 'createReferencePreview default title', ( assert ) => {
|
||||
renderer.registerPreviewUI(
|
||||
previewTypes.TYPE_REFERENCE,
|
||||
renderer.createReferencePreview
|
||||
);
|
||||
const model = {
|
||||
url: '',
|
||||
extract: '',
|
||||
type: previewTypes.TYPE_REFERENCE
|
||||
},
|
||||
preview = renderer.createPreviewWithType( model );
|
||||
|
||||
assert.strictEqual(
|
||||
$( preview.el ).find( '.mwe-popups-title' ).text().trim(),
|
||||
'<popups-refpreview-reference>'
|
||||
);
|
||||
} );
|
||||
|
||||
QUnit.test( 'createReferencePreview updates fade-out effect on scroll', ( assert ) => {
|
||||
renderer.registerPreviewUI(
|
||||
previewTypes.TYPE_REFERENCE,
|
||||
renderer.createReferencePreview
|
||||
);
|
||||
const model = {
|
||||
url: '',
|
||||
extract: '',
|
||||
type: previewTypes.TYPE_REFERENCE
|
||||
},
|
||||
preview = renderer.createPreviewWithType( model ),
|
||||
$extract = $( preview.el ).find( '.mwe-popups-extract' );
|
||||
|
||||
$extract.children()[ 0 ].dispatchEvent( new Event( 'scroll' ) );
|
||||
|
||||
assert.false( $extract.children()[ 0 ].isScrolling );
|
||||
assert.false( $extract.hasClass( 'mwe-popups-fade-out' ) );
|
||||
} );
|
||||
|
||||
QUnit.test( 'bindBehavior - preview dwell', function ( assert ) {
|
||||
const preview = createPagePreview(),
|
||||
behavior = createBehavior( this.sandbox );
|
||||
|
|
|
@ -28,7 +28,10 @@ module.exports = ( env, argv ) => ( {
|
|||
// working directory.
|
||||
context: __dirname,
|
||||
|
||||
entry: { index: './src' },
|
||||
entry: {
|
||||
index: './src',
|
||||
referencePreviews: './src/ext.popups.referencePreviews/index.js'
|
||||
},
|
||||
|
||||
resolve: {
|
||||
alias: {
|
||||
|
@ -119,8 +122,8 @@ module.exports = ( env, argv ) => ( {
|
|||
// Minified uncompressed size limits for chunks / assets and entrypoints. Keep these numbers
|
||||
// up-to-date and rounded to the nearest 10th of a kibibyte so that code sizing costs are
|
||||
// well understood. Related to bundlesize minified, gzipped compressed file size tests.
|
||||
maxAssetSize: 47.8 * 1024,
|
||||
maxEntrypointSize: 47.8 * 1024,
|
||||
maxAssetSize: 40.0 * 1024,
|
||||
maxEntrypointSize: 40.0 * 1024,
|
||||
|
||||
// The default filter excludes map files but we rename ours.
|
||||
assetFilter: ( filename ) => !filename.endsWith( srcMapExt )
|
||||
|
|
Loading…
Reference in a new issue