Merge "[JavaScript] Validate types"

This commit is contained in:
jenkins-bot 2020-03-16 15:59:53 +00:00 committed by Gerrit Code Review
commit 8d65373883
12 changed files with 193 additions and 81 deletions

View File

@ -4,5 +4,9 @@
"wikimedia/client",
"wikimedia/jquery",
"wikimedia/mediawiki"
]
],
"rules": {
// Interferes with @type annotations.
"one-var": "off"
}
}

View File

@ -3,11 +3,11 @@ Each portal has the following composition:
string portal-id
string html-tooltip
string msg-label-id
string|null html-userlangattributes
string msg-label}
string? html-userlangattributes
string msg-label
string html-portal-content
string|null html-after-portal
string|null html-hook-vector-after-toolbox is deprecated and used by the toolbox portal.
string? html-after-portal
string? html-hook-vector-after-toolbox is deprecated and used by the toolbox portal.
}}
<div class="portal" role="navigation" id="{{portal-id}}" {{{html-tooltip}}} aria-labelledby="{{msg-label-id}}">
<h3 {{{html-userlangattributes}}} id="{{msg-label-id}}">

84
package-lock.json generated
View File

@ -1455,12 +1455,27 @@
"integrity": "sha512-iTs9HReBu7evG77Q4EC8hZnqRt57irBDkK9nvmHroiOIVwYMQc4IvYvdRgwKfYepunIY7Oh/dBuuld+Gj9uo6w==",
"dev": true
},
"@types/jquery": {
"version": "3.3.33",
"resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.3.33.tgz",
"integrity": "sha512-U6IdXYGkfUI42SR79vB2Spj+h1Ly3J3UZjpd8mi943lh126TK7CB+HZOxGh2nM3IySor7wqVQdemD/xtydsBKA==",
"dev": true,
"requires": {
"@types/sizzle": "*"
}
},
"@types/minimist": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-aaI6OtKcrwCX8G7aWbNh7i8GOfY=",
"dev": true
},
"@types/mustache": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@types/mustache/-/mustache-4.0.1.tgz",
"integrity": "sha512-wH6Tu9mbiOt0n5EvdoWy0VGQaJMHfLIxY/6wS0xLC7CV1taM6gESEzcYy0ZlWvxxiiljYvfDIvz4hHbUUDRlhw==",
"dev": true
},
"@types/node": {
"version": "13.9.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-13.9.1.tgz",
@ -1529,6 +1544,12 @@
"@types/react": "*"
}
},
"@types/sizzle": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.2.tgz",
"integrity": "sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg==",
"dev": true
},
"@types/unist": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.3.tgz",
@ -2125,8 +2146,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
"dev": true,
"optional": true
"dev": true
},
"assign-symbols": {
"version": "1.0.0",
@ -3430,7 +3450,6 @@
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dev": true,
"optional": true,
"requires": {
"delayed-stream": "~1.0.0"
}
@ -3938,8 +3957,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
"dev": true,
"optional": true
"dev": true
},
"delegate": {
"version": "3.2.0",
@ -5148,8 +5166,7 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
"dev": true,
"optional": true
"dev": true
},
"fast-deep-equal": {
"version": "2.0.1",
@ -5613,8 +5630,7 @@
"ansi-regex": {
"version": "2.1.1",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"aproba": {
"version": "1.2.0",
@ -5635,14 +5651,12 @@
"balanced-match": {
"version": "1.0.0",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@ -5657,20 +5671,17 @@
"code-point-at": {
"version": "1.1.0",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"core-util-is": {
"version": "1.0.2",
@ -5787,8 +5798,7 @@
"inherits": {
"version": "2.0.4",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"ini": {
"version": "1.3.5",
@ -5800,7 +5810,6 @@
"version": "1.0.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@ -5815,7 +5824,6 @@
"version": "3.0.4",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@ -5823,14 +5831,12 @@
"minimist": {
"version": "0.0.8",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"minipass": {
"version": "2.9.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
@ -5849,7 +5855,6 @@
"version": "0.5.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
}
@ -5939,8 +5944,7 @@
"number-is-nan": {
"version": "1.0.1",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"object-assign": {
"version": "4.1.1",
@ -5952,7 +5956,6 @@
"version": "1.4.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"wrappy": "1"
}
@ -6038,8 +6041,7 @@
"safe-buffer": {
"version": "5.1.2",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"safer-buffer": {
"version": "2.1.2",
@ -6075,7 +6077,6 @@
"version": "1.0.2",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@ -6095,7 +6096,6 @@
"version": "3.0.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@ -6139,14 +6139,12 @@
"wrappy": {
"version": "1.0.2",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"yallist": {
"version": "3.1.1",
"bundled": true,
"dev": true,
"optional": true
"dev": true
}
}
},
@ -7391,8 +7389,7 @@
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
"dev": true,
"optional": true
"dev": true
},
"jsdoc": {
"version": "3.6.3",
@ -11871,8 +11868,7 @@
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
"dev": true,
"optional": true
"dev": true
},
"type-check": {
"version": "0.3.2",
@ -11920,6 +11916,12 @@
"is-typedarray": "^1.0.0"
}
},
"typescript": {
"version": "3.8.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz",
"integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==",
"dev": true
},
"uc.micro": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",

View File

@ -2,7 +2,7 @@
"private": true,
"scripts": {
"build": "npm -s test && npm -s run doc",
"test": "npm -s run lint",
"test": "npm -s run lint && tsc",
"lint": "npm -s run lint:js && npm -s run lint:styles && npm -s run lint:i18n",
"lint:fix": "npm -s run lint:js -- --fix && npm -s run lint:styles -- --fix",
"lint:js": "eslint --cache --max-warnings 0 .",
@ -16,6 +16,8 @@
"devDependencies": {
"@babel/core": "7.7.7",
"@storybook/html": "5.2.8",
"@types/jquery": "3.3.33",
"@types/mustache": "4.0.1",
"babel-loader": "8.0.6",
"eslint-config-wikimedia": "0.15.0",
"grunt-banana-checker": "0.8.1",
@ -26,6 +28,7 @@
"mustache": "3.0.1",
"pre-commit": "1.2.2",
"stylelint-config-wikimedia": "0.9.0",
"svgo": "1.3.2"
"svgo": "1.3.2",
"typescript": "3.8.3"
}
}

34
resources/CollapsibleTabsPlugin.d.ts vendored Normal file
View File

@ -0,0 +1,34 @@
interface JQueryStatic {
collapsibleTabs: CollapsibleTabsStatic;
}
interface JQuery {
collapsibleTabs(options: Partial<CollapsibleTabsOptions>): void;
}
/** A jQuery plugin that makes collapsible tabs for the Vector skin. */
interface CollapsibleTabsOptions {
/** Optional tab selector. Defaults to `#p-views ul`. */
expandedContainer: string;
/** Optional menu item selector. Defaults to `#p-cactions ul`. */
collapsedContainer: string;
/** Optional selector for tabs that are collapsible. Defaults to `li.collapsible`. */
collapsible: string;
shifting: boolean;
expandedWidth: number;
expandCondition(eleWidth: number): boolean;
collapseCondition(): boolean;
}
interface CollapsibleTabsStatic {
defaults: CollapsibleTabsOptions;
instances: JQuery[];
addData($collapsible: JQuery): void;
getSettings($collapsible: JQuery): CollapsibleTabsOptions;
handleResize(): void;
moveToCollapsed($moving: JQuery): void;
moveToExpanded($moving: JQuery): void;
calculateTabDistance(): number;
}
interface CollapsibleTabs extends CollapsibleTabsStatic, CollapsibleTabsOptions {}

20
resources/mediawiki.d.ts vendored Normal file
View File

@ -0,0 +1,20 @@
interface MediaWiki {
util: {
/**
* Return a wrapper function that is debounced for the given duration.
*
* When it is first called, a timeout is scheduled. If before the timer
* is reached the wrapper is called again, it gets rescheduled for the
* same duration from now until it stops being called. The original function
* is called from the "tail" of such chain, with the last set of arguments.
*
* @since 1.34
* @param {number} delay Time in milliseconds
* @param {Function} callback
* @return {Function}
*/
debounce(delay: number, callback: Function): () => void;
};
}
declare const mw: MediaWiki;

View File

@ -1,19 +1,9 @@
/** @interface CollapsibleTabsOptions */
( function () {
var boundEvent,
isRTL = document.documentElement.dir === 'rtl',
rAF = window.requestAnimationFrame || setTimeout;
/** @type {boolean|undefined} */ var boundEvent;
var isRTL = document.documentElement.dir === 'rtl';
var rAF = window.requestAnimationFrame || setTimeout;
/**
* A jQuery plugin that makes collapsible tabs for the Vector skin.
*
* @class jQuery.plugin.collapsibleTabs
* @param {Object} [options]
* @param {string} [options.expandedContainer=#p-views ul] List of tabs
* @param {string} [options.collapsedContainer=#p-cactions ul] List of menu items
* @param {string} [options.collapsible=li.collapsible] Match tabs that are collapsible
* @param {Function} [options.expandCondition]
* @param {Function} [options.collapseCondition]
*/
$.fn.collapsibleTabs = function ( options ) {
// Merge options into the defaults
var settings = $.extend( {}, $.collapsibleTabs.defaults, options );
@ -54,6 +44,7 @@
collapsedContainer: '#p-cactions ul',
collapsible: 'li.collapsible',
shifting: false,
expandedWidth: 0,
expandCondition: function ( eleWidth ) {
// If there are at least eleWidth + 1 pixels of free space, expand.
// We add 1 because .width() will truncate fractional values but .offset() will not.
@ -125,19 +116,21 @@
} );
},
moveToCollapsed: function ( $moving ) {
var outerData, expContainerSettings, target;
/** @type {CollapsibleTabsOptions} */ var outerData;
/** @type {CollapsibleTabsOptions} */ var collapsedContainerSettings;
/** @type {string} */ var target;
outerData = $.collapsibleTabs.getSettings( $moving );
if ( !outerData ) {
return;
}
expContainerSettings = $.collapsibleTabs.getSettings(
collapsedContainerSettings = $.collapsibleTabs.getSettings(
$( outerData.expandedContainer )
);
if ( !expContainerSettings ) {
if ( !collapsedContainerSettings ) {
return;
}
expContainerSettings.shifting = true;
collapsedContainerSettings.shifting = true;
// Remove the element from where it's at and put it in the dropdown menu
target = outerData.collapsedContainer;
@ -150,22 +143,26 @@
$( '<span>' ).addClass( 'placeholder' ).css( 'display', 'none' ).insertAfter( this );
$( this ).detach().prependTo( target ).data( 'collapsibleTabsSettings', outerData );
$( this ).attr( 'style', 'display: list-item;' );
expContainerSettings.shifting = false;
collapsedContainerSettings.shifting = false;
rAF( $.collapsibleTabs.handleResize );
} );
},
moveToExpanded: function ( $moving ) {
var data, expContainerSettings, $target, expandedWidth;
/** @type {CollapsibleTabsOptions} */ var data;
/** @type {CollapsibleTabsOptions} */ var expandedContainerSettings;
var $target;
var expandedWidth;
data = $.collapsibleTabs.getSettings( $moving );
if ( !data ) {
return;
}
expContainerSettings = $.collapsibleTabs.getSettings( $( data.expandedContainer ) );
if ( !expContainerSettings ) {
expandedContainerSettings =
$.collapsibleTabs.getSettings( $( data.expandedContainer ) );
if ( !expandedContainerSettings ) {
return;
}
expContainerSettings.shifting = true;
expandedContainerSettings.shifting = true;
// grab the next appearing placeholder so we can use it for replacing
$target = $( data.expandedContainer ).find( 'span.placeholder' ).first();
@ -184,9 +181,9 @@
// change the tab's contents after the page load *gasp* (T71729). This
// doesn't prevent a tab from collapsing back and forth once, but at
// least it won't continue to do that forever.
data.expandedWidth = $moving.width();
data.expandedWidth = $moving.width() || 0;
$moving.data( 'collapsibleTabsSettings', data );
expContainerSettings.shifting = false;
expandedContainerSettings.shifting = false;
$.collapsibleTabs.handleResize();
} );
} )
@ -215,10 +212,12 @@
leftTab = document.getElementById( 'right-navigation' );
rightTab = document.getElementById( 'left-navigation' );
}
leftEnd = leftTab.getBoundingClientRect().right;
rightStart = rightTab.getBoundingClientRect().left;
return rightStart - leftEnd;
if ( leftTab && rightTab ) {
leftEnd = leftTab.getBoundingClientRect().right;
rightStart = rightTab.getBoundingClientRect().left;
return rightStart - leftEnd;
}
return 0;
}
};
}() );

View File

@ -14,7 +14,7 @@ $( function () {
// must not return 0 if hidden, but rather virtually render it
// and compute its width, then hide it again. jQuery width() does
// all that for us.
var width = $cactions.width();
var width = $cactions.width() || 0;
initialCactionsWidth = function () {
return width;
};
@ -98,8 +98,8 @@ $( function () {
// 3. and, the left-navigation and right-navigation are overlapping
// each other, e.g. when making the window very narrow, or if a gadget
// added a lot of tabs.
$tabContainer.children( 'li.collapsible' ).each( function ( index, element ) {
collapsibleWidth += $( element ).width();
$tabContainer.children( 'li.collapsible' ).each( function ( _index, element ) {
collapsibleWidth += $( element ).width() || 0;
if ( collapsibleWidth > initialCactionsWidth() ) {
// We've found one or more collapsible links that are wider
// than the "More" menu would be if it were made visible,
@ -108,6 +108,7 @@ $( function () {
// Stop this possibly expensive loop the moment the condition is met once.
return false;
}
return;
} );
return doCollapse;
}

View File

@ -4,6 +4,22 @@ import '../resources/skins.vector.styles/Portal.less';
import '../.storybook/common.less';
import { placeholder, htmluserlangattributes } from './utils';
/**
* @typedef {Object} PortletContext
* @prop {string} portal-id
* @prop {string} html-tooltip
* @prop {string} msg-label-id
* @prop {string} [html-userlangattributes]
* @prop {string} msg-label
* @prop {string} html-portal-content
* @prop {string} [html-after-portal]
* @prop {string} [html-hook-vector-after-toolbox] Deprecated and used by the toolbox portal.
*/
/**
* @param {PortletContext} data
* @return {HTMLElement}
*/
export const wrapPortlet = ( data ) => {
const node = document.createElement( 'div' );
node.setAttribute( 'id', 'mw-panel' );
@ -11,6 +27,10 @@ export const wrapPortlet = ( data ) => {
return node;
};
/**
* @param {string} html
* @return {string}
*/
const portletAfter = ( html ) => {
return `<div class="after-portlet after-portlet-tb">${html}</div>`;
};
@ -33,6 +53,7 @@ export const PORTALS = {
},
navigation: {
'portal-id': 'p-navigation',
'html-tooltip': 'A message tooltip-p-navigation must exist for this to appear',
'msg-label': 'Navigation',
'msg-label-id': 'p-navigation-label',
'html-userlangattributes': htmluserlangattributes,
@ -71,7 +92,7 @@ ${placeholder( `<p>Further hook output possible (lang)</p>`, 60 )}`
},
otherProjects: {
'portal-id': 'p-wikibase-otherprojects',
'html-tooltip': 'A message tooltip-p-lang must exist for this to appear',
'html-tooltip': 'A message tooltip-p-wikibase-otherprojects must exist for this to appear',
'msg-label': 'In other projects',
'msg-label-id': 'p-wikibase-otherprojects-label',
'html-userlangattributes': htmluserlangattributes,

4
stories/rawLoader.d.ts vendored Normal file
View File

@ -0,0 +1,4 @@
declare module "!!raw-loader!*" {
const src: string;
export default src;
}

View File

@ -1,3 +1,8 @@
/**
* @param {string} msg
* @param {number} [height=200]
* @return {string}
*/
const placeholder = ( msg, height ) => {
return `<div style="width: 100%; height: ${height || 200}px; margin-bottom: 2px;
font-size: 12px; padding: 8px; box-sizing: border-box;

19
tsconfig.json Normal file
View File

@ -0,0 +1,19 @@
{
"exclude": ["docs", "vendor"],
"compilerOptions": {
"resolveJsonModule": true,
"esModuleInterop": true,
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"newLine": "lf",
"forceConsistentCasingInFileNames": true,
"pretty": true,
"target": "es5",
"lib": ["dom"],
"allowJs": true,
"checkJs": true,
"noEmit": true
}
}