Commit 3920b09a authored by Samuel Hilson's avatar Samuel Hilson

Merge branch 'update/133/Popups' into 'master'

Update Popups for 1.33

See merge request !61
parents f3673701 619a65a0
{
"presets": [
[
"env",
{
// Do not transform modules to CommonJS.
"modules": false,
// See modern tier: https://www.mediawiki.org/wiki/Compatibility#Browser_support_matrix
"targets": {
// https://en.wikipedia.org/wiki/Google_Chrome_version_history
"chrome": "64",
"ie": "11",
// https://en.wikipedia.org/wiki/Firefox_version_history
"firefox": "58",
"safari": "5.1",
"opera": "15",
"ios": "6.1",
"android": "4.1"
}
}
]
]
"presets": ["@babel/preset-env"]
}
# See Grade A in resource loader startup module mediawikicore resources/src/startup/startup.js
# https//en.wikipedia.org/wiki/Google_Chrome_version_history
chrome 13
ie 11
# https//en.wikipedia.org/wiki/Firefox_version_history
firefox 4.0
safari 5.0
opera 15
ios 6.0
android 4.1
......@@ -13,6 +13,8 @@
"camelcase": 0,
"spaced-comment": 0,
"space-in-parens": 0,
"switch-colon-spacing": 0,
"no-prototype-builtins": 0,
"block-spacing": 0,
"object-curly-spacing": 0,
"eol-last": 0,
......@@ -47,6 +49,10 @@
"new-parens": 0,
"no-fallthrough": 0,
"no-implicit-coercion": 0,
"no-catch-shadow": 0
"no-catch-shadow": 0,
"max-statements-per-line": 0,
"no-bitwise": 0,
"no-loop-func": 0,
"no-new-func": 0
}
}
{
"extends": "wikimedia",
"root": true,
"extends": [
"wikimedia/client",
"wikimedia/jquery"
],
"parserOptions": {
"sourceType": "module",
"ecmaVersion": "5"
"ecmaVersion": "6"
},
"env": {
"browser": true,
"jquery": true,
"commonjs": true,
"qunit": true
"commonjs": true
},
"globals": {
"mediaWiki": false,
"OO": false,
"moment": false,
"Redux": false,
"ReduxThunk": false
"mediaWiki": "readonly",
"OO": "readonly"
},
"rules": {
"no-prototype-builtins": 0,
"no-restricted-properties": [2,
{
"object": "$",
......@@ -25,26 +26,21 @@
"message": "Please use Array.forEach"
}
],
"valid-jsdoc": ["error", {
"requireParamDescription": false,
"requireReturnDescription": false,
"preferType": {
"Boolean": "boolean",
"Number": "number",
"object": "Object",
"String": "string"
}
}],
"dot-notation": [ 2, { "allowKeywords": true } ],
"no-use-before-define": 0,
"no-var": 2,
"prefer-const": 1,
"prefer-template": 1,
"one-var": 0, // Interferes with prefer-const.
"max-len": [
1,
{
"tabWidth": 2,
// Exclude by default:
// - `eslint-` directives. To avoid having to disable
// eslint for a long eslint-disable line.
"ignorePattern": "^// eslint-.+",
"ignoreUrls": true,
"ignoreComments": false,
"ignoreRegExpLiterals": true,
"ignoreStrings": true,
"ignoreTemplateLiterals": true
}
]
"one-var": 0
}
}
/doc/autogenerated/
/coverage/
/docs/js/
/.nyc_output/
/node_modules/
/vendor/
/composer.lock
/.eslintcache
/.storybook/node_modules
/.storybook/dist
{
"//": "todo: enable caching. There are too many other issues to verify that",
"//": "caching works correctly.",
"cache": false,
"//": "todo: check coverage on all files not just those included in tests.",
"//": "Enable when",
"//": "https://github.com/istanbuljs/nyc/issues/537#issuecomment-390814662",
"//": "is fixed.",
"all": false,
"//": "Ignore files in vendor/, resources/, and elsewhere.",
"include": [ "src/**/*.js" ],
"//": "Set the coverage percentage by category thresholds.",
"statements": 90,
"branches": 80,
"functions": 85,
"lines": 90,
"//": "Fail if the coverage is below threshold.",
"check-coverage": true,
"//": "Work around source maps being included ",
"//": "https://github.com/istanbuljs/nyc/issues/847:",
"//": " Error: ENAMETOOLONG: name too long, open '.../vagrant/mediawiki/extensions/Popups/src/data:application/json;...'",
"//": "Unfortunately, the reported line numbers appear to be",
"//": "nondeterministic across runs when all is enabled and incorrect when",
"//": "disabled.",
"sourceMap": false
}
<?xml version="1.0"?>
<ruleset>
<rule ref="./vendor/mediawiki/mediawiki-codesniffer/MediaWiki">
<exclude name="Squiz.Scope.MethodScope.Missing" />
</rule>
<file>.</file>
<arg name="extensions" value="php,php5,inc" />
<arg name="encoding" value="UTF-8" />
<rule ref="./vendor/mediawiki/mediawiki-codesniffer/MediaWiki" />
<rule ref="Squiz.Functions.FunctionDeclarationArgumentSpacing">
<rule ref="Squiz.Strings.DoubleQuoteUsage">
<exclude name="Squiz.Strings.DoubleQuoteUsage.ContainsVar" />
</rule>
<rule ref="Squiz.WhiteSpace.FunctionSpacing">
<properties>
<property name="equalsSpacing" value="1" />
<property name="requiredSpacesAfterOpen" value="1" />
<property name="requiredSpacesBeforeClose" value="1" />
<property name="spacing" value="1" />
</properties>
</rule>
<file>.</file>
<arg name="extensions" value="php,php5,inc" />
<arg name="encoding" value="UTF-8" />
</ruleset>
# StoryPops - Storybook for Popups
This "mini-project" contains all the dependencies and code to run a
Storybook app (https://storybook.js.org/) for the Popups repository.
**Quickstart:**
`npm install && npm run start` visit http://localhost:6006
NOTE: This project requires a different version of Node then the main Popups project. NVM is recommended to manage these versions.
(`cd .storybook && nvm use`)
This project is configured to run separately from the main Popups project
because it requires at least Node v8.4, whereas Popups (currently)
runs Node 6 for consistency with C.I.
When the Popups Node version is upgraded, the Storybook dependencies
can be moved into the main Popups package.json file and the one in
this folder can be removed.
/**
* This file is required to register add-ons with Storybook.
*/
import '@storybook/addon-options/register';
import '@storybook/addon-knobs/register';
import '@storybook/addon-cssresources/register';
import { configure, addDecorator } from '@storybook/html';
import { withOptions } from '@storybook/addon-options';
import { withCssResources } from '@storybook/addon-cssresources';
/**
* Storybook global configuration
*/
addDecorator(
withCssResources({
cssresources: [{
name: `x-ray`,
code: `<style>
body * {
outline: 1px solid rgb(255, 0, 0);
background-color: rgba(255, 0, 0, 0.07);}
</style>`,
picked: false,
}],
})
);
// Option defaults:
addDecorator(
withOptions({
/**
* name to display in the top left corner
* @type {String}
*/
name: 'Popups',
/**
* URL for name in top left corner to link to
* @type {String}
*/
url: '#',
/**
* show story component as full screen
* @type {Boolean}
*/
goFullScreen: false,
/**
* display panel that shows a list of stories
* @type {Boolean}
*/
showStoriesPanel: true,
/**
* display panel that shows addon configurations
* @type {Boolean}
*/
showAddonPanel: true,
/**
* display floating search box to search through stories
* @type {Boolean}
*/
showSearchBox: false,
/**
* show addon panel as a vertical panel on the right
* @type {Boolean}
*/
addonPanelInRight: true,
/**
* sorts stories
* @type {Boolean}
*/
sortStoriesByKind: false,
/**
* regex for finding the hierarchy separator
* @example:
* null - turn off hierarchy
* /\// - split by `/`
* /\./ - split by `.`
* /\/|\./ - split by `/` or `.`
* @type {Regex}
*/
hierarchySeparator: null,
/**
* regex for finding the hierarchy root separator
* @example:
* null - turn off multiple hierarchy roots
* /\|/ - split by `|`
* @type {Regex}
*/
hierarchyRootSeparator: null,
/**
* sidebar tree animations
* @type {Boolean}
*/
sidebarAnimations: true,
/**
* id to select an addon panel
* @type {String}
*/
selectedAddonPanel: undefined, // The order of addons in the "Addon panel" is the same as you import them in 'addons.js'. The first panel will be opened by default as you run Storybook
/**
* enable/disable shortcuts
* @type {Boolean}
*/
enableShortcuts: true, // true by default
})
);
// automatically import all files ending in *.stories.js
const req = require.context('./stories', true, /.stories.js$/);
function loadStories() {
req.keys().forEach(filename => req(filename));
}
configure(loadStories, module);
import { SIZES } from '../../src/ui/thumbnail';
import { createPreviewWithType, layoutPreview, getClasses } from '../../src/ui/renderer.js';
import scaleDownThumbnail from './scaleDownThumbnail';
const POINTER_SIZE = 8;
/**
* Creates a static/stateless Popup and returns its HTML.
*
* @param {ext.popups.PreviewModel} model
* @param {object} layout
*
* @returns {string} HTML
*/
function createPopup( model, layout ) {
if ( model.thumbnail ) {
model.thumbnail = scaleDownThumbnail( model.thumbnail );
}
const preview = createPreviewWithType( model );
Object.assign( layout, { dir: model.languageDirection } );
layoutPreview(
preview,
layout,
getClasses( preview, {
flippedX: layout.flippedX,
flippedY: layout.flippedY
} ),
SIZES.landscapeImage.h,
POINTER_SIZE
);
return preview.el[ 0 ].outerHTML;
}
export default createPopup;
/**
* Grid helper for absolutely positioning popups on page.
*/
const grid = {
landscape: {
row: ( x ) => 50 + ( ( x - 1 ) * 300 ),
col: ( x ) => 50 + ( ( x - 1 ) * 500 )
},
portrait: {
row: ( x ) => 50 + ( ( x - 1 ) * 450 ),
col: ( x ) => 50 + ( ( x - 1 ) * 400 )
},
}
export default grid;
/**
* Popups thumbnails are requested from the server at a size
* relative to the screen DPI. Since we're not making that
* server request, instead using predefined models, we have to
* scale the thumbnail dimensions down manually for low-dpi displays.
*
* We're only scaling images down and not up since the correct
* behaviour for popup is to not display an image if it's too small.
* An image that's too big wouldn't be requested in the first place.
*
* It's best to define hi-dpi images in the models, unless the purpose
* is to display the thumbnail on a low-dpi display and not a hi-dpi one.
*/
import { default as CONSTANTS } from '../../src/constants';
/**
* Scaled down thumbnails for low-dpi displays.
* @param {Object} thumbnail - PagePreviewModel.thumbnail property
* @returns {Object} PagePreviewModel.thumbnail property
*/
export default function scaleDownThumbnail( thumbnail ) {
const
x = thumbnail.width,
y = thumbnail.height,
ratio = Math.min(CONSTANTS.THUMBNAIL_SIZE / x, CONSTANTS.THUMBNAIL_SIZE / y),
thumbSrc = thumbnail.source,
maxPxSize = CONSTANTS.THUMBNAIL_SIZE + 'px',
scaledSrc = thumbSrc.replace( /\d*.px/, maxPxSize );
return Object.assign({}, thumbnail, {
source: scaledSrc,
width: x * ratio,
height: y * ratio,
});
}
/**
* Mocks out various mediawiki.js functionality to avoid the mw dependency.
*/
const messages = require( '../../../i18n/en.json');
module.exports = {
msg: function ( key ) {
return messages[ key ];
},
Title: function( string ) {
return {
getUrl: function(){ return string }
};
},
html: {
escape: function( str ){
return str
}
}
};
# LESS imports from Mediawiki-core
The following files:
- mediawiki.mixins
- mediawiki.mixins.animation
- mediawiki.mixins.less
are LESS files containing one-line imports that correspond to files in
mediawiki-core. This file structure is required to mimick ResourceLoaders
LESS module-import behaviour.
ResourceLoader can resolve LESS modules with file paths like `@import "mediawiki.ui/variables"`.
Webpack however, cannot do this easily. The default LESS resolver requires
files ending in ".less", and although webpack can create an alias to a
module, that alias cannot include a path separator.
The webpack LESS-loader treats imports that don't begin with a relative or
absolute filepath as coming from the current directory (.i.e. "./").
However it provides an option to specify a custom module resolution path.
That path is set to this folder, and LESS files that can't be resolved by
either relative or absolute paths are searched for here.
Since this custom resolver requires also requires a ".less" extension,
files are duplicated so that "mediawiki.mixins" and "mediawiki.mixins.less"
can both be resolved.
/**
* These are custom styles designed to supplement styles produced
* by ResourceLoad or MediaWiki-core.
**/
@import '../../../../../resources/src/mediawiki.ui/components/icons.less';
html, body {
height: 100%;
font-family: sans-serif;
}
/**
* Stopping the fade animation to avoid the animation appearing
* whenever a user types into the "knob" fields and the popup rerenders.
* NOTE: To test the animation, remove these rules.
*/
.mwe-popups-fade-in-up {
-webkit-animation: none;
animation: none;
}
.mwe-popups-fade-in-down {
-webkit-animation: none;
animation: none;
}
/* show popups by default */
.mwe-popups {
display: block;
}
/* Settings icon generated by resourceLoader */
.mw-ui-icon-popups-settings:before {
background: linear-gradient(transparent,transparent), url('../../../resources/ext.popups.images/cog.svg');
}
/**
* This file reaches into mediawiki-core and imports a LESS file
* in order to resolve `@import "mediawiki.mixins"` statements in Popups LESS files.
*/
@import '../../../../../resources/src/mediawiki.less/mediawiki.mixins.less';
/**
* This file reaches into mediawiki-core and imports a LESS file in order to
* resolve `@import "mediawiki.mixins.animation.less"` statements in Popups LESS files.
*/
@import '../../../../../resources/src/mediawiki.less/mediawiki.mixins.animation.less';
/**
* This file reaches into mediawiki-core and imports a LESS file in order to
* resolve `@import "mediawiki.mixins.less"` statements in Popups LESS files.
*/
@import '../../../../../resources/src/mediawiki.less/mediawiki.mixins.less';
/**
* This file reaches into mediawiki-core and imports a LESS file in order to
* resolve `@import "mediawiki.ui/variables"` statements in Popups LESS files.
*/
@import '../../../../../../resources/src/mediawiki.less/mediawiki.ui/variables.less';
This diff is collapsed.
This diff is collapsed.
{
"private": true,
"scripts": {
"start": "start-storybook --config-dir=. -p 6006",
"build": "build-storybook -c . -o dist"
},
"devDependencies": {
"@babel/core": "7.1.6",
"@storybook/addon-cssresources": "4.1.0-alpha.9",
"@storybook/addon-knobs": "4.0.9",
"@storybook/addon-options": "4.0.12",
"@storybook/html": "4.0.9",
"@storybook/react": "4.0.12",
"babel-loader": "8.0.4",
"expose-loader": "0.7.5",
"jquery": "3.3.1",
"less": "3.8.1",
"less-loader": "4.1.0",
"svg-inline-loader": "0.8.0",
"url-loader": "1.1.2"
}
}
This diff is collapsed.
const path = require("path");
const webpack = require('webpack');
module.exports = {
module: {
rules: [ {
test: /\.less$/,
use: [{
loader: 'style-loader'
}, {
loader: 'css-loader'
}, {
loader: 'less-loader',
options: {
paths: [
/**
* Less files are resolved to this path,
* which contain less files that essentially
* just reach into mediawiki core fo the
* appropriate files.
*/
path.resolve(__dirname, './mocks/less')
]
}
}],
},
{
test: /\.svg$/,
issuer: /\.less$/,
loader: 'url-loader'
},
{
test: /\.svg$/,
loader: 'svg-inline-loader',
issuer: /\.js$/,