Compare commits
26 Commits
Author | SHA1 | Date | |
---|---|---|---|
ba236c4753 | |||
a204f7c1dd | |||
bacf9122de | |||
2fdc1eac94 | |||
5fd4391cd9 | |||
6991358428 | |||
b050fde276 | |||
32444c9851 | |||
b93dcc43ad | |||
6ff6ff1673 | |||
e1ff86820c | |||
7d22c361d1 | |||
951cccb6b0 | |||
438e425838 | |||
ddb5ad071e | |||
38060d986c | |||
8c74396459 | |||
a09d63e8f8 | |||
d74af9a73d | |||
60310693d3 | |||
5d08821c9b | |||
3316e40e7b | |||
dfe5985326 | |||
b27ad17c59 | |||
14b8b24e14 | |||
711fc5835f |
23
CHANGELOG.md
23
CHANGELOG.md
@ -1,3 +1,26 @@
|
|||||||
|
### v3.6.8
|
||||||
|
|
||||||
|
- Typings: add FullscreenOptions.container to typing files (thanks @MeguminSama!)
|
||||||
|
- Fix: added iPadOS detection to isIos util (thanks @Benny739!)
|
||||||
|
- Fix: issues with Vimeo fullscreen
|
||||||
|
|
||||||
|
### v3.6.7
|
||||||
|
|
||||||
|
- Fix: remove regression caused by optional chaining and nullish coalescing in check for `window.CSS` check for aspect-ratio (fixes #2174)
|
||||||
|
|
||||||
|
### v3.6.6
|
||||||
|
|
||||||
|
- Improvements to how aspect ratio is handled. Use `aspect-ratio` CSS property instead of the legacy method (still used as fallback). Also automatically determined aspect ratios are rounded to the nearast standard ratio. This fixes issues with the YouTube embeds showing a 1-2px black bar.
|
||||||
|
- Hide the YouTube poster image container when paused so that the controls underneath can be used.
|
||||||
|
|
||||||
|
### v3.6.5
|
||||||
|
|
||||||
|
- Migrate color formatting to colorette (thanks @jorgebucaran)
|
||||||
|
- Fix: issue with IE detection
|
||||||
|
- Fix: missing styles for embeds
|
||||||
|
- Fix: regression regarding poster image
|
||||||
|
- Add all required props to vimeo iframe allow attribute - fixes #2151 (thanks @didrip)
|
||||||
|
|
||||||
### v3.6.4
|
### v3.6.4
|
||||||
|
|
||||||
- Remove unnecessary calc from media query (thanks @naomiaz)
|
- Remove unnecessary calc from media query (thanks @naomiaz)
|
||||||
|
@ -134,13 +134,13 @@ See [initialising](#initialising) for more information on advanced setups.
|
|||||||
You can use our CDN (provided by [Fastly](https://www.fastly.com/)) for the JavaScript. There's 2 versions; one with and one without [polyfills](#polyfills). My recommendation would be to manage polyfills seperately as part of your application but to make life easier you can use the polyfilled build.
|
You can use our CDN (provided by [Fastly](https://www.fastly.com/)) for the JavaScript. There's 2 versions; one with and one without [polyfills](#polyfills). My recommendation would be to manage polyfills seperately as part of your application but to make life easier you can use the polyfilled build.
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<script src="https://cdn.plyr.io/3.6.4/plyr.js"></script>
|
<script src="https://cdn.plyr.io/3.6.8/plyr.js"></script>
|
||||||
```
|
```
|
||||||
|
|
||||||
...or...
|
...or...
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<script src="https://cdn.plyr.io/3.6.4/plyr.polyfilled.js"></script>
|
<script src="https://cdn.plyr.io/3.6.8/plyr.polyfilled.js"></script>
|
||||||
```
|
```
|
||||||
|
|
||||||
## CSS
|
## CSS
|
||||||
@ -154,13 +154,13 @@ Include the `plyr.css` stylsheet into your `<head>`.
|
|||||||
If you want to use our CDN (provided by [Fastly](https://www.fastly.com/)) for the default CSS, you can use the following:
|
If you want to use our CDN (provided by [Fastly](https://www.fastly.com/)) for the default CSS, you can use the following:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<link rel="stylesheet" href="https://cdn.plyr.io/3.6.4/plyr.css" />
|
<link rel="stylesheet" href="https://cdn.plyr.io/3.6.8/plyr.css" />
|
||||||
```
|
```
|
||||||
|
|
||||||
## SVG Sprite
|
## SVG Sprite
|
||||||
|
|
||||||
The SVG sprite is loaded automatically from our CDN (provided by [Fastly](https://www.fastly.com/)). To change this, see the [options](#options) below. For
|
The SVG sprite is loaded automatically from our CDN (provided by [Fastly](https://www.fastly.com/)). To change this, see the [options](#options) below. For
|
||||||
reference, the CDN hosted SVG sprite can be found at `https://cdn.plyr.io/3.6.4/plyr.svg`.
|
reference, the CDN hosted SVG sprite can be found at `https://cdn.plyr.io/3.6.8/plyr.svg`.
|
||||||
|
|
||||||
# Ads
|
# Ads
|
||||||
|
|
||||||
@ -839,6 +839,7 @@ Plyr costs money to run, not only my time. I donate my time for free as I enjoy
|
|||||||
- [Rutheneum-Bote](https://gymnasium-rutheneum.de/content/newspaper/kreativwettbewerb.php)
|
- [Rutheneum-Bote](https://gymnasium-rutheneum.de/content/newspaper/kreativwettbewerb.php)
|
||||||
- [pressakey.com | Blog-Magazin für Videospiele](https://pressakey.com)
|
- [pressakey.com | Blog-Magazin für Videospiele](https://pressakey.com)
|
||||||
- [STROLLÿN: Work with a View](https://strollyn.com)
|
- [STROLLÿN: Work with a View](https://strollyn.com)
|
||||||
|
- [CFDA Runway360](https://runway360.cfda.com/)
|
||||||
|
|
||||||
If you want to be added to the list, open a pull request. It'd be awesome to see how you're using Plyr 😎
|
If you want to be added to the list, open a pull request. It'd be awesome to see how you're using Plyr 😎
|
||||||
|
|
||||||
|
@ -2,4 +2,4 @@
|
|||||||
// Layout
|
// Layout
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
$container-max-width: 1260px;
|
$container-max-width: 1240px;
|
||||||
|
46
package.json
46
package.json
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "plyr",
|
"name": "plyr",
|
||||||
"version": "3.6.4",
|
"version": "3.6.8",
|
||||||
"description": "A simple, accessible and customizable HTML5, YouTube and Vimeo media player",
|
"description": "A simple, accessible and customizable HTML5, YouTube and Vimeo media player",
|
||||||
"homepage": "https://plyr.io",
|
"homepage": "https://plyr.io",
|
||||||
"author": "Sam Potts <sam@potts.es>",
|
"author": "Sam Potts <sam@potts.es>",
|
||||||
@ -39,19 +39,19 @@
|
|||||||
"start": "gulp"
|
"start": "gulp"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@sampotts/eslint-config": "1.1.5",
|
"@sampotts/eslint-config": "1.1.7",
|
||||||
"ansi-colors": "^4.1.1",
|
"autoprefixer": "^10.2.5",
|
||||||
"autoprefixer": "^10.0.2",
|
"aws-sdk": "^2.888.0",
|
||||||
"aws-sdk": "^2.814.0",
|
"@babel/core": "^7.13.15",
|
||||||
"@babel/core": "^7.12.10",
|
"@babel/preset-env": "^7.13.15",
|
||||||
"@babel/preset-env": "^7.12.11",
|
"@babel/plugin-proposal-class-properties": "^7.13.0",
|
||||||
"@babel/plugin-proposal-class-properties": "^7.12.1",
|
|
||||||
"babel-eslint": "^10.1.0",
|
"babel-eslint": "^10.1.0",
|
||||||
"browser-sync": "^2.26.13",
|
"browser-sync": "^2.26.14",
|
||||||
|
"colorette": "1.2.2",
|
||||||
|
"cssnano": "^5.0.1",
|
||||||
"del": "^6.0.0",
|
"del": "^6.0.0",
|
||||||
"eslint": "^7.3.1",
|
"eslint": "^7.23.0",
|
||||||
"fancy-log": "^1.3.3",
|
"fancy-log": "^1.3.3",
|
||||||
"fastly-purge": "^1.0.1",
|
|
||||||
"git-branch": "^2.0.1",
|
"git-branch": "^2.0.1",
|
||||||
"gulp": "^4.0.2",
|
"gulp": "^4.0.2",
|
||||||
"gulp-awspublish": "^4.1.2",
|
"gulp-awspublish": "^4.1.2",
|
||||||
@ -70,29 +70,27 @@
|
|||||||
"gulp-size": "^3.0.0",
|
"gulp-size": "^3.0.0",
|
||||||
"gulp-sourcemaps": "^3.0.0",
|
"gulp-sourcemaps": "^3.0.0",
|
||||||
"gulp-svgstore": "^7.0.1",
|
"gulp-svgstore": "^7.0.1",
|
||||||
"gulp-terser": "^2.0.0",
|
"gulp-terser": "^2.0.1",
|
||||||
"postcss": "^8.1.7",
|
"postcss": "^8.2.10",
|
||||||
"postcss-clean": "^1.1.0",
|
"postcss-custom-properties": "^11.0.0",
|
||||||
"postcss-custom-properties": "^10.0.0",
|
|
||||||
"prettier-eslint": "^12.0.0",
|
"prettier-eslint": "^12.0.0",
|
||||||
"prettier-stylelint": "^0.4.2",
|
"prettier-stylelint": "^0.4.2",
|
||||||
"remark-cli": "^9.0.0",
|
"remark-cli": "^9.0.0",
|
||||||
"remark-validate-links": "^10.0.2",
|
"remark-validate-links": "^10.0.4",
|
||||||
"rollup": "^2.35.1",
|
"rollup": "^2.45.2",
|
||||||
"rollup-plugin-babel": "^4.4.0",
|
"rollup-plugin-babel": "^4.4.0",
|
||||||
"rollup-plugin-commonjs": "^10.1.0",
|
"rollup-plugin-commonjs": "^10.1.0",
|
||||||
"rollup-plugin-node-resolve": "^5.2.0",
|
"rollup-plugin-node-resolve": "^5.2.0",
|
||||||
"stylelint": "^13.8.0",
|
"stylelint": "^13.12.0",
|
||||||
"stylelint-config-prettier": "^8.0.2",
|
"stylelint-config-prettier": "^8.0.2",
|
||||||
"stylelint-config-recommended": "^3.0.0",
|
"stylelint-config-recommended": "^4.0.0",
|
||||||
"stylelint-config-sass-guidelines": "^7.1.0",
|
"stylelint-config-sass-guidelines": "^8.0.0",
|
||||||
"stylelint-order": "^4.1.0",
|
"stylelint-order": "^4.1.0",
|
||||||
"stylelint-scss": "^3.18.0",
|
"stylelint-scss": "^3.19.0",
|
||||||
"stylelint-selector-bem-pattern": "^2.1.0",
|
"stylelint-selector-bem-pattern": "^2.1.0"
|
||||||
"through2": "^4.0.2"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"core-js": "^3.8.1",
|
"core-js": "^3.10.1",
|
||||||
"custom-event-polyfill": "^1.0.7",
|
"custom-event-polyfill": "^1.0.7",
|
||||||
"loadjs": "^4.2.0",
|
"loadjs": "^4.2.0",
|
||||||
"rangetouch": "^2.0.1",
|
"rangetouch": "^2.0.1",
|
||||||
|
@ -61,7 +61,7 @@ const defaults = {
|
|||||||
// Sprite (for icons)
|
// Sprite (for icons)
|
||||||
loadSprite: true,
|
loadSprite: true,
|
||||||
iconPrefix: 'plyr',
|
iconPrefix: 'plyr',
|
||||||
iconUrl: 'https://cdn.plyr.io/3.6.4/plyr.svg',
|
iconUrl: 'https://cdn.plyr.io/3.6.8/plyr.svg',
|
||||||
|
|
||||||
// Blank video (used to prevent errors on source change)
|
// Blank video (used to prevent errors on source change)
|
||||||
blankVideo: 'https://cdn.plyr.io/static/blank.mp4',
|
blankVideo: 'https://cdn.plyr.io/static/blank.mp4',
|
||||||
|
@ -10,7 +10,7 @@ import { getElement, getElements, matches, toggleClass } from './utils/elements'
|
|||||||
import { off, on, once, toggleListener, triggerEvent } from './utils/events';
|
import { off, on, once, toggleListener, triggerEvent } from './utils/events';
|
||||||
import is from './utils/is';
|
import is from './utils/is';
|
||||||
import { silencePromise } from './utils/promise';
|
import { silencePromise } from './utils/promise';
|
||||||
import { getAspectRatio, setAspectRatio } from './utils/style';
|
import { getAspectRatio, getViewportSize, supportsCSS } from './utils/style';
|
||||||
|
|
||||||
class Listeners {
|
class Listeners {
|
||||||
constructor(player) {
|
constructor(player) {
|
||||||
@ -149,16 +149,16 @@ class Listeners {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
/* case 73:
|
/* case 73:
|
||||||
this.setLoop('start');
|
this.setLoop('start');
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 76:
|
case 76:
|
||||||
this.setLoop();
|
this.setLoop();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 79:
|
case 79:
|
||||||
this.setLoop('end');
|
this.setLoop('end');
|
||||||
break; */
|
break; */
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -305,39 +305,49 @@ class Listeners {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Set a gutter for Vimeo
|
// Set a gutter for Vimeo
|
||||||
const setGutter = (ratio, padding, toggle) => {
|
const setGutter = () => {
|
||||||
if (!player.isVimeo || player.config.vimeo.premium) {
|
if (!player.isVimeo || player.config.vimeo.premium) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const target = player.elements.wrapper.firstChild;
|
const target = elements.wrapper;
|
||||||
const [, y] = ratio;
|
const { active } = player.fullscreen;
|
||||||
const [videoX, videoY] = getAspectRatio.call(player);
|
const [videoWidth, videoHeight] = getAspectRatio.call(player);
|
||||||
|
const useNativeAspectRatio = supportsCSS(`aspect-ratio: ${videoWidth} / ${videoHeight}`);
|
||||||
|
|
||||||
target.style.maxWidth = toggle ? `${(y / videoY) * videoX}px` : null;
|
// If not active, remove styles
|
||||||
target.style.margin = toggle ? '0 auto' : null;
|
if (!active) {
|
||||||
};
|
if (useNativeAspectRatio) {
|
||||||
|
target.style.width = null;
|
||||||
// Resize on fullscreen change
|
target.style.height = null;
|
||||||
const setPlayerSize = (measure) => {
|
} else {
|
||||||
// If we don't need to measure the viewport
|
target.style.maxWidth = null;
|
||||||
if (!measure) {
|
target.style.margin = null;
|
||||||
return setAspectRatio.call(player);
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const rect = elements.container.getBoundingClientRect();
|
// Determine which dimension will overflow and constrain view
|
||||||
const { width, height } = rect;
|
const [viewportWidth, viewportHeight] = getViewportSize();
|
||||||
|
const overflow = viewportWidth / viewportHeight > videoWidth / videoHeight;
|
||||||
|
|
||||||
return setAspectRatio.call(player, `${width}:${height}`);
|
if (useNativeAspectRatio) {
|
||||||
|
target.style.width = overflow ? 'auto' : '100%';
|
||||||
|
target.style.height = overflow ? '100%' : 'auto';
|
||||||
|
} else {
|
||||||
|
target.style.maxWidth = overflow ? `${(viewportHeight / videoHeight) * videoWidth}px` : null;
|
||||||
|
target.style.margin = overflow ? '0 auto' : null;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Handle resizing
|
||||||
const resized = () => {
|
const resized = () => {
|
||||||
clearTimeout(timers.resized);
|
clearTimeout(timers.resized);
|
||||||
timers.resized = setTimeout(setPlayerSize, 50);
|
timers.resized = setTimeout(setGutter, 50);
|
||||||
};
|
};
|
||||||
|
|
||||||
on.call(player, elements.container, 'enterfullscreen exitfullscreen', (event) => {
|
on.call(player, elements.container, 'enterfullscreen exitfullscreen', (event) => {
|
||||||
const { target, usingNative } = player.fullscreen;
|
const { target } = player.fullscreen;
|
||||||
|
|
||||||
// Ignore events not from target
|
// Ignore events not from target
|
||||||
if (target !== elements.container) {
|
if (target !== elements.container) {
|
||||||
@ -349,26 +359,12 @@ class Listeners {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isEnter = event.type === 'enterfullscreen';
|
|
||||||
// Set the player size when entering fullscreen to viewport size
|
|
||||||
const { padding, ratio } = setPlayerSize(isEnter);
|
|
||||||
|
|
||||||
// Set Vimeo gutter
|
// Set Vimeo gutter
|
||||||
setGutter(ratio, padding, isEnter);
|
setGutter();
|
||||||
|
|
||||||
// Horrible hack for Safari 14 not repainting properly on entering fullscreen
|
// Watch for resizes
|
||||||
if (isEnter) {
|
const method = event.type === 'enterfullscreen' ? on : off;
|
||||||
setTimeout(() => repaint(elements.container), 100);
|
method.call(player, window, 'resize', resized);
|
||||||
}
|
|
||||||
|
|
||||||
// If not using native browser fullscreen API, we need to check for resizes of viewport
|
|
||||||
if (!usingNative) {
|
|
||||||
if (isEnter) {
|
|
||||||
on.call(player, window, 'resize', resized);
|
|
||||||
} else {
|
|
||||||
off.call(player, window, 'resize', resized);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -41,7 +41,6 @@ const media = {
|
|||||||
// Poster image container
|
// Poster image container
|
||||||
this.elements.poster = createElement('div', {
|
this.elements.poster = createElement('div', {
|
||||||
class: this.config.classNames.poster,
|
class: this.config.classNames.poster,
|
||||||
hidden: '',
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.elements.wrapper.appendChild(this.elements.poster);
|
this.elements.wrapper.appendChild(this.elements.poster);
|
||||||
|
@ -11,7 +11,7 @@ import fetch from '../utils/fetch';
|
|||||||
import is from '../utils/is';
|
import is from '../utils/is';
|
||||||
import loadScript from '../utils/load-script';
|
import loadScript from '../utils/load-script';
|
||||||
import { format, stripHTML } from '../utils/strings';
|
import { format, stripHTML } from '../utils/strings';
|
||||||
import { setAspectRatio } from '../utils/style';
|
import { roundAspectRatio, setAspectRatio } from '../utils/style';
|
||||||
import { buildUrlParams } from '../utils/urls';
|
import { buildUrlParams } from '../utils/urls';
|
||||||
|
|
||||||
// Parse Vimeo ID from URL
|
// Parse Vimeo ID from URL
|
||||||
@ -104,7 +104,10 @@ const vimeo = {
|
|||||||
const src = format(player.config.urls.vimeo.iframe, id, params);
|
const src = format(player.config.urls.vimeo.iframe, id, params);
|
||||||
iframe.setAttribute('src', src);
|
iframe.setAttribute('src', src);
|
||||||
iframe.setAttribute('allowfullscreen', '');
|
iframe.setAttribute('allowfullscreen', '');
|
||||||
iframe.setAttribute('allow', ['autoplay', 'fullscreen', 'picture-in-picture'].join('; '));
|
iframe.setAttribute(
|
||||||
|
'allow',
|
||||||
|
['autoplay', 'fullscreen', 'picture-in-picture', 'encrypted-media', 'accelerometer', 'gyroscope'].join('; '),
|
||||||
|
);
|
||||||
|
|
||||||
// Set the referrer policy if required
|
// Set the referrer policy if required
|
||||||
if (!is.empty(referrerPolicy)) {
|
if (!is.empty(referrerPolicy)) {
|
||||||
@ -291,7 +294,7 @@ const vimeo = {
|
|||||||
// Set aspect ratio based on video size
|
// Set aspect ratio based on video size
|
||||||
Promise.all([player.embed.getVideoWidth(), player.embed.getVideoHeight()]).then((dimensions) => {
|
Promise.all([player.embed.getVideoWidth(), player.embed.getVideoHeight()]).then((dimensions) => {
|
||||||
const [width, height] = dimensions;
|
const [width, height] = dimensions;
|
||||||
player.embed.ratio = [width, height];
|
player.embed.ratio = roundAspectRatio(width, height);
|
||||||
setAspectRatio.call(this);
|
setAspectRatio.call(this);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ import loadImage from '../utils/load-image';
|
|||||||
import loadScript from '../utils/load-script';
|
import loadScript from '../utils/load-script';
|
||||||
import { extend } from '../utils/objects';
|
import { extend } from '../utils/objects';
|
||||||
import { format, generateId } from '../utils/strings';
|
import { format, generateId } from '../utils/strings';
|
||||||
import { setAspectRatio } from '../utils/style';
|
import { roundAspectRatio, setAspectRatio } from '../utils/style';
|
||||||
|
|
||||||
// Parse YouTube ID from URL
|
// Parse YouTube ID from URL
|
||||||
function parseId(url) {
|
function parseId(url) {
|
||||||
@ -90,7 +90,7 @@ const youtube = {
|
|||||||
ui.setTitle.call(this);
|
ui.setTitle.call(this);
|
||||||
|
|
||||||
// Set aspect ratio
|
// Set aspect ratio
|
||||||
this.embed.ratio = [width, height];
|
this.embed.ratio = roundAspectRatio(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
setAspectRatio.call(this);
|
setAspectRatio.call(this);
|
||||||
|
1
src/js/plyr.d.ts
vendored
1
src/js/plyr.d.ts
vendored
@ -549,6 +549,7 @@ declare namespace Plyr {
|
|||||||
fallback?: boolean | 'force';
|
fallback?: boolean | 'force';
|
||||||
allowAudio?: boolean;
|
allowAudio?: boolean;
|
||||||
iosNative?: boolean;
|
iosNative?: boolean;
|
||||||
|
container?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CaptionOptions {
|
interface CaptionOptions {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
// Plyr
|
// Plyr
|
||||||
// plyr.js v3.6.4
|
// plyr.js v3.6.8
|
||||||
// https://github.com/sampotts/plyr
|
// https://github.com/sampotts/plyr
|
||||||
// License: The MIT License (MIT)
|
// License: The MIT License (MIT)
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
@ -29,7 +29,7 @@ import loadSprite from './utils/load-sprite';
|
|||||||
import { clamp } from './utils/numbers';
|
import { clamp } from './utils/numbers';
|
||||||
import { cloneDeep, extend } from './utils/objects';
|
import { cloneDeep, extend } from './utils/objects';
|
||||||
import { silencePromise } from './utils/promise';
|
import { silencePromise } from './utils/promise';
|
||||||
import { getAspectRatio, reduceAspectRatio, setAspectRatio, validateRatio } from './utils/style';
|
import { getAspectRatio, reduceAspectRatio, setAspectRatio, validateAspectRatio } from './utils/style';
|
||||||
import { parseUrl } from './utils/urls';
|
import { parseUrl } from './utils/urls';
|
||||||
|
|
||||||
// Private properties
|
// Private properties
|
||||||
@ -916,12 +916,12 @@ class Plyr {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is.string(input) || !validateRatio(input)) {
|
if (!is.string(input) || !validateAspectRatio(input)) {
|
||||||
this.debug.error(`Invalid aspect ratio specified (${input})`);
|
this.debug.error(`Invalid aspect ratio specified (${input})`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.config.ratio = input;
|
this.config.ratio = reduceAspectRatio(input);
|
||||||
|
|
||||||
setAspectRatio.call(this);
|
setAspectRatio.call(this);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
// Plyr Polyfilled Build
|
// Plyr Polyfilled Build
|
||||||
// plyr.js v3.6.4
|
// plyr.js v3.6.8
|
||||||
// https://github.com/sampotts/plyr
|
// https://github.com/sampotts/plyr
|
||||||
// License: The MIT License (MIT)
|
// License: The MIT License (MIT)
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
@ -4,11 +4,13 @@
|
|||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
const browser = {
|
const browser = {
|
||||||
isIE: /* @cc_on!@ */ false || !!document.documentMode,
|
isIE: Boolean(window.document.documentMode),
|
||||||
isEdge: window.navigator.userAgent.includes('Edge'),
|
isEdge: window.navigator.userAgent.includes('Edge'),
|
||||||
isWebkit: 'WebkitAppearance' in document.documentElement.style && !/Edge/.test(navigator.userAgent),
|
isWebkit: 'WebkitAppearance' in document.documentElement.style && !/Edge/.test(navigator.userAgent),
|
||||||
isIPhone: /(iPhone|iPod)/gi.test(navigator.platform),
|
isIPhone: /(iPhone|iPod)/gi.test(navigator.platform),
|
||||||
isIos: /(iPad|iPhone|iPod)/gi.test(navigator.platform),
|
isIos:
|
||||||
|
(navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1) ||
|
||||||
|
/(iPad|iPhone|iPod)/gi.test(navigator.platform),
|
||||||
};
|
};
|
||||||
|
|
||||||
export default browser;
|
export default browser;
|
||||||
|
@ -2,9 +2,39 @@
|
|||||||
// Style utils
|
// Style utils
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
|
import { closest } from './arrays';
|
||||||
import is from './is';
|
import is from './is';
|
||||||
|
|
||||||
export function validateRatio(input) {
|
// Check support for a CSS declaration
|
||||||
|
export function supportsCSS(declaration) {
|
||||||
|
if (!window || !window.CSS) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return window.CSS.supports(declaration);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Standard/common aspect ratios
|
||||||
|
const standardRatios = [
|
||||||
|
[1, 1],
|
||||||
|
[4, 3],
|
||||||
|
[3, 4],
|
||||||
|
[5, 4],
|
||||||
|
[4, 5],
|
||||||
|
[3, 2],
|
||||||
|
[2, 3],
|
||||||
|
[16, 10],
|
||||||
|
[10, 16],
|
||||||
|
[16, 9],
|
||||||
|
[9, 16],
|
||||||
|
[21, 9],
|
||||||
|
[9, 21],
|
||||||
|
[32, 9],
|
||||||
|
[9, 32],
|
||||||
|
].reduce((out, [x, y]) => ({ ...out, [x / y]: [x, y] }), {});
|
||||||
|
|
||||||
|
// Validate an aspect ratio
|
||||||
|
export function validateAspectRatio(input) {
|
||||||
if (!is.array(input) && (!is.string(input) || !input.includes(':'))) {
|
if (!is.array(input) && (!is.string(input) || !input.includes(':'))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -14,6 +44,7 @@ export function validateRatio(input) {
|
|||||||
return ratio.map(Number).every(is.number);
|
return ratio.map(Number).every(is.number);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reduce an aspect ratio to it's lowest form
|
||||||
export function reduceAspectRatio(ratio) {
|
export function reduceAspectRatio(ratio) {
|
||||||
if (!is.array(ratio) || !ratio.every(is.number)) {
|
if (!is.array(ratio) || !ratio.every(is.number)) {
|
||||||
return null;
|
return null;
|
||||||
@ -26,8 +57,9 @@ export function reduceAspectRatio(ratio) {
|
|||||||
return [width / divider, height / divider];
|
return [width / divider, height / divider];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculate an aspect ratio
|
||||||
export function getAspectRatio(input) {
|
export function getAspectRatio(input) {
|
||||||
const parse = (ratio) => (validateRatio(ratio) ? ratio.split(':').map(Number) : null);
|
const parse = (ratio) => (validateAspectRatio(ratio) ? ratio.split(':').map(Number) : null);
|
||||||
// Try provided ratio
|
// Try provided ratio
|
||||||
let ratio = parse(input);
|
let ratio = parse(input);
|
||||||
|
|
||||||
@ -44,10 +76,10 @@ export function getAspectRatio(input) {
|
|||||||
// Get from HTML5 video
|
// Get from HTML5 video
|
||||||
if (ratio === null && this.isHTML5) {
|
if (ratio === null && this.isHTML5) {
|
||||||
const { videoWidth, videoHeight } = this.media;
|
const { videoWidth, videoHeight } = this.media;
|
||||||
ratio = reduceAspectRatio([videoWidth, videoHeight]);
|
ratio = [videoWidth, videoHeight];
|
||||||
}
|
}
|
||||||
|
|
||||||
return ratio;
|
return reduceAspectRatio(ratio);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set aspect ratio for responsive container
|
// Set aspect ratio for responsive container
|
||||||
@ -58,10 +90,20 @@ export function setAspectRatio(input) {
|
|||||||
|
|
||||||
const { wrapper } = this.elements;
|
const { wrapper } = this.elements;
|
||||||
const ratio = getAspectRatio.call(this, input);
|
const ratio = getAspectRatio.call(this, input);
|
||||||
const [w, h] = is.array(ratio) ? ratio : [0, 0];
|
|
||||||
const padding = (100 / w) * h;
|
|
||||||
|
|
||||||
wrapper.style.paddingBottom = `${padding}%`;
|
if (!is.array(ratio)) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const [x, y] = reduceAspectRatio(ratio);
|
||||||
|
const useNative = supportsCSS(`aspect-ratio: ${x}/${y}`);
|
||||||
|
const padding = (100 / x) * y;
|
||||||
|
|
||||||
|
if (useNative) {
|
||||||
|
wrapper.style.aspectRatio = `${x}/${y}`;
|
||||||
|
} else {
|
||||||
|
wrapper.style.paddingBottom = `${padding}%`;
|
||||||
|
}
|
||||||
|
|
||||||
// For Vimeo we have an extra <div> to hide the standard controls and UI
|
// For Vimeo we have an extra <div> to hide the standard controls and UI
|
||||||
if (this.isVimeo && !this.config.vimeo.premium && this.supported.ui) {
|
if (this.isVimeo && !this.config.vimeo.premium && this.supported.ui) {
|
||||||
@ -74,10 +116,30 @@ export function setAspectRatio(input) {
|
|||||||
this.media.style.transform = `translateY(-${offset}%)`;
|
this.media.style.transform = `translateY(-${offset}%)`;
|
||||||
}
|
}
|
||||||
} else if (this.isHTML5) {
|
} else if (this.isHTML5) {
|
||||||
wrapper.classList.toggle(this.config.classNames.videoFixedRatio, ratio !== null);
|
wrapper.classList.add(this.config.classNames.videoFixedRatio);
|
||||||
}
|
}
|
||||||
|
|
||||||
return { padding, ratio };
|
return { padding, ratio };
|
||||||
}
|
}
|
||||||
|
|
||||||
export default { setAspectRatio };
|
// Round an aspect ratio to closest standard ratio
|
||||||
|
export function roundAspectRatio(x, y, tolerance = 0.05) {
|
||||||
|
const ratio = x / y;
|
||||||
|
const closestRatio = closest(Object.keys(standardRatios), ratio);
|
||||||
|
|
||||||
|
// Check match is within tolerance
|
||||||
|
if (Math.abs(closestRatio - ratio) <= tolerance) {
|
||||||
|
return standardRatios[closestRatio];
|
||||||
|
}
|
||||||
|
|
||||||
|
// No match
|
||||||
|
return [x, y];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the size of the viewport
|
||||||
|
// https://stackoverflow.com/questions/1248081/how-to-get-the-browser-viewport-dimensions
|
||||||
|
export function getViewportSize() {
|
||||||
|
const width = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0);
|
||||||
|
const height = Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0);
|
||||||
|
return [width, height];
|
||||||
|
}
|
||||||
|
@ -20,3 +20,8 @@
|
|||||||
.plyr--stopped.plyr__poster-enabled .plyr__poster {
|
.plyr--stopped.plyr__poster-enabled .plyr__poster {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Allow interaction with YouTube controls while paused
|
||||||
|
.plyr--youtube.plyr--paused.plyr__poster-enabled:not(.plyr--stopped) .plyr__poster {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
@ -59,17 +59,6 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.plyr__video-wrapper {
|
|
||||||
height: 100%;
|
|
||||||
position: static;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Vimeo requires some different styling
|
|
||||||
&.plyr--vimeo .plyr__video-wrapper {
|
|
||||||
height: 0;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Display correct icon
|
// Display correct icon
|
||||||
.plyr__control .icon--exit-fullscreen {
|
.plyr__control .icon--exit-fullscreen {
|
||||||
display: block;
|
display: block;
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
|
|
||||||
.plyr__video-wrapper {
|
.plyr__video-wrapper {
|
||||||
background: var(--plyr-video-background, $plyr-video-background);
|
background: var(--plyr-video-background, $plyr-video-background);
|
||||||
height: 100%;
|
|
||||||
margin: auto;
|
margin: auto;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -26,29 +25,32 @@ $embed-padding: ((100 / 16) * 9);
|
|||||||
|
|
||||||
.plyr__video-embed,
|
.plyr__video-embed,
|
||||||
.plyr__video-wrapper--fixed-ratio {
|
.plyr__video-wrapper--fixed-ratio {
|
||||||
height: 0;
|
@supports not (aspect-ratio: 16 / 9) {
|
||||||
padding-bottom: to-percentage($embed-padding);
|
height: 0;
|
||||||
|
padding-bottom: to-percentage($embed-padding);
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
aspect-ratio: 16 / 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
.plyr__video-embed iframe,
|
.plyr__video-embed iframe,
|
||||||
.plyr__video-wrapper--fixed-ratio video {
|
.plyr__video-wrapper--fixed-ratio video {
|
||||||
border: 0;
|
border: 0;
|
||||||
|
height: 100%;
|
||||||
left: 0;
|
left: 0;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the full custom UI is supported
|
// For Vimeo, if the full custom UI is supported
|
||||||
.plyr--full-ui .plyr__video-embed {
|
.plyr--full-ui .plyr__video-embed > .plyr__video-embed__container {
|
||||||
$height: 240;
|
$height: 240;
|
||||||
$offset: to-percentage(($height - $embed-padding) / ($height / 50));
|
$offset: to-percentage(($height - $embed-padding) / ($height / 50));
|
||||||
|
padding-bottom: to-percentage($height);
|
||||||
// Only used for Vimeo
|
position: relative;
|
||||||
> .plyr__video-embed__container {
|
transform: translateY(-$offset);
|
||||||
padding-bottom: to-percentage($height);
|
|
||||||
position: relative;
|
|
||||||
transform: translateY(-$offset);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Controls container
|
// Controls container
|
||||||
|
@ -16,7 +16,7 @@ const resolve = require('rollup-plugin-node-resolve');
|
|||||||
const sass = require('gulp-sass');
|
const sass = require('gulp-sass');
|
||||||
const postcss = require('gulp-postcss');
|
const postcss = require('gulp-postcss');
|
||||||
const autoprefixer = require('autoprefixer');
|
const autoprefixer = require('autoprefixer');
|
||||||
const clean = require('postcss-clean');
|
const cssnano = require('cssnano');
|
||||||
const customprops = require('postcss-custom-properties');
|
const customprops = require('postcss-custom-properties');
|
||||||
// Images
|
// Images
|
||||||
const svgstore = require('gulp-svgstore');
|
const svgstore = require('gulp-svgstore');
|
||||||
@ -158,7 +158,15 @@ Object.entries(build.css).forEach(([filename, entry]) => {
|
|||||||
.src(src)
|
.src(src)
|
||||||
.pipe(plumber())
|
.pipe(plumber())
|
||||||
.pipe(sass())
|
.pipe(sass())
|
||||||
.pipe(postcss([customprops(), autoprefixer(), clean()]))
|
.pipe(
|
||||||
|
postcss([
|
||||||
|
customprops(),
|
||||||
|
autoprefixer(),
|
||||||
|
cssnano({
|
||||||
|
preset: 'default',
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
)
|
||||||
.pipe(size(sizeOptions))
|
.pipe(size(sizeOptions))
|
||||||
.pipe(gulp.dest(dist)),
|
.pipe(gulp.dest(dist)),
|
||||||
);
|
);
|
||||||
|
@ -10,15 +10,13 @@ const gulp = require('gulp');
|
|||||||
const gitbranch = require('git-branch');
|
const gitbranch = require('git-branch');
|
||||||
const rename = require('gulp-rename');
|
const rename = require('gulp-rename');
|
||||||
const replace = require('gulp-replace');
|
const replace = require('gulp-replace');
|
||||||
const ansi = require('ansi-colors');
|
const { green, cyan, bold } = require('colorette');
|
||||||
const log = require('fancy-log');
|
const log = require('fancy-log');
|
||||||
const open = require('gulp-open');
|
const open = require('gulp-open');
|
||||||
const size = require('gulp-size');
|
const size = require('gulp-size');
|
||||||
const through = require('through2');
|
|
||||||
// Deployment
|
// Deployment
|
||||||
const aws = require('aws-sdk');
|
const aws = require('aws-sdk');
|
||||||
const publish = require('gulp-awspublish');
|
const publish = require('gulp-awspublish');
|
||||||
const FastlyPurge = require('fastly-purge');
|
|
||||||
// Configs
|
// Configs
|
||||||
const pkg = require('../package.json');
|
const pkg = require('../package.json');
|
||||||
const deploy = require('../deploy.json');
|
const deploy = require('../deploy.json');
|
||||||
@ -53,14 +51,6 @@ const paths = {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get credentials
|
|
||||||
let credentials = {};
|
|
||||||
try {
|
|
||||||
credentials = require('../credentials.json'); //eslint-disable-line
|
|
||||||
} catch (e) {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get branch info
|
// Get branch info
|
||||||
const branch = {
|
const branch = {
|
||||||
current: gitbranch.sync(),
|
current: gitbranch.sync(),
|
||||||
@ -128,7 +118,7 @@ gulp.task('version', (done) => {
|
|||||||
|
|
||||||
const { domain } = deploy.cdn;
|
const { domain } = deploy.cdn;
|
||||||
|
|
||||||
log(`Updating version in files to ${ansi.green.bold(version)}...`);
|
log(`Updating version in files to ${green(bold(version))}...`);
|
||||||
|
|
||||||
// Replace versioned URLs in source
|
// Replace versioned URLs in source
|
||||||
const files = ['plyr.js', 'plyr.polyfilled.js', 'config/defaults.js'];
|
const files = ['plyr.js', 'plyr.polyfilled.js', 'config/defaults.js'];
|
||||||
@ -156,7 +146,7 @@ gulp.task('cdn', (done) => {
|
|||||||
throw new Error('No publisher instance. Check AWS configuration.');
|
throw new Error('No publisher instance. Check AWS configuration.');
|
||||||
}
|
}
|
||||||
|
|
||||||
log(`Uploading ${ansi.green.bold(pkg.version)} to ${ansi.cyan(domain)}...`);
|
log(`Uploading ${green(bold(pkg.version))} to ${cyan(domain)}...`);
|
||||||
|
|
||||||
// Upload to CDN
|
// Upload to CDN
|
||||||
return (
|
return (
|
||||||
@ -177,41 +167,6 @@ gulp.task('cdn', (done) => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Purge the fastly cache incase any 403/404 are cached
|
|
||||||
gulp.task('purge', () => {
|
|
||||||
if (!Object.keys(credentials).includes('fastly')) {
|
|
||||||
throw new Error('Fastly credentials required to purge cache.');
|
|
||||||
}
|
|
||||||
|
|
||||||
const { fastly } = credentials;
|
|
||||||
const list = [];
|
|
||||||
|
|
||||||
return gulp
|
|
||||||
.src(paths.upload)
|
|
||||||
.pipe(
|
|
||||||
through.obj((file, enc, cb) => {
|
|
||||||
const filename = file.path.split('/').pop();
|
|
||||||
list.push(`${versionPath}${filename.replace(minSuffix, '')}`);
|
|
||||||
cb(null);
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.on('end', () => {
|
|
||||||
const purge = new FastlyPurge(fastly.token);
|
|
||||||
|
|
||||||
list.forEach((url) => {
|
|
||||||
log(`Purging ${ansi.cyan(url)}...`);
|
|
||||||
|
|
||||||
purge.url(url, (error, result) => {
|
|
||||||
if (error) {
|
|
||||||
log.error(error);
|
|
||||||
} else if (result) {
|
|
||||||
log(result);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Publish to demo bucket
|
// Publish to demo bucket
|
||||||
gulp.task('demo', (done) => {
|
gulp.task('demo', (done) => {
|
||||||
if (!canDeploy()) {
|
if (!canDeploy()) {
|
||||||
@ -226,7 +181,7 @@ gulp.task('demo', (done) => {
|
|||||||
throw new Error('No publisher instance. Check AWS configuration.');
|
throw new Error('No publisher instance. Check AWS configuration.');
|
||||||
}
|
}
|
||||||
|
|
||||||
log(`Uploading ${ansi.green.bold(pkg.version)} to ${ansi.cyan(domain)}...`);
|
log(`Uploading ${green(bold(pkg.version))} to ${cyan(domain)}...`);
|
||||||
|
|
||||||
// Replace versioned files in README.md
|
// Replace versioned files in README.md
|
||||||
gulp
|
gulp
|
||||||
@ -271,4 +226,4 @@ gulp.task('open', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Do everything
|
// Do everything
|
||||||
gulp.task('deploy', gulp.series('cdn', 'demo', 'purge', 'open'));
|
gulp.task('deploy', gulp.series('cdn', 'demo', 'open'));
|
||||||
|
Reference in New Issue
Block a user