Compare commits

...

18 Commits

Author SHA1 Message Date
Sam Potts b444aa3a98 pkg: deploy v3.6.3 2020-11-14 13:29:47 +11:00
Sam Potts e8d883edba v3.6.3 (#2016)
* force fullscreen events to trigger on plyr element (media element in iOS) and not fullscreen container

* Fixing "missing code in detail" for PlyrEvent type

When using typescript and listening for youtube statechange event, it is missing the code property definition inside the event (even though it is provided in the code).
By making events a map of key-value, we can add easily custom event type for specific event name. Since YouTube "statechange" event differs from the basic PlyrEvent, I added a new Event Type "PlyrStateChangeEvent" having a code property corresponding to a YoutubeState enum defined by the YouTube API documentation.
This pattern follows how addEventListener in the lib.dom.d.ts is defined.

* Update link to working dash.js demo (was broken)

* Fix PreviewThumbnailsOptions type

According to the docs, the `src` should also accept an array of strings.

* fix issue #1872

* Check if key is a string before attempt --plyr checking

* Fix for Slow loading videos not autoplaying

* Fix for Slow loading videos not autoplaying

* Network requests are not cancelled after the player is destroyed

* Fix for apect ratio problem when using Vimeo player on mobile devices (issue #1940)

* chore: update packages and linting

* Invoke custom listener on triggering fullscreen via double-click

* Fix volume when unmuting from volume 0

* adding a nice Svelte plugin that I found

* Add missing unit to calc in media query

* Assigning player's lastSeekTime on rewind/fast forward to prevent immediate controls hide on mobile

* Fix youtube not working when player is inside shadow dom

* v3.6.2

* ESLint to use common config

* add BitChute to users list

* Fix aspect ratio issue

* Revert noCookie change

* feat: demo radius tweaks

* fix: poster image shouldn’t receive click events

* chore: package updates

* chore: linting

* feat: custom controls option for embedded players

* Package upgrades

* ESLint to use common config

* Linting changes

* Update README.md

* chore: formatting

* fix: revert pointer events change for poster

* fix: hack for Safari 14 not repainting Vimeo embed on entering fullscreen

* fix: demo using custom controls for YouTube

* doc: Add STROLLÿN among the list of Plyr users

* Fixes #2005

* fix: overflowing volume slider

* chore: clean up CSS

* fix: hide poster when not using custom controls

* Package upgrades

* ESLint to use common config

* Linting changes

* chore: revert customControls default option (to prevent breaking change)

* docs: changelog for v3.6.3

Co-authored-by: Som Meaden <som@theprojectsomething.com>
Co-authored-by: akuma06 <demon.akuma06@gmail.com>
Co-authored-by: Jonathan Arbely <dev@jonathanarbely.de>
Co-authored-by: Takeshi <iwatakeshi@users.noreply.github.com>
Co-authored-by: Hex <hex@codeigniter.org.cn>
Co-authored-by: Syed Husain <syed.husain@appspace.com>
Co-authored-by: Danielh112 <Daniel@sbgsportssoftware.com>
Co-authored-by: Danil Stoyanov <d.stoyanov@corp.mail.ru>
Co-authored-by: Guru Prasad Srinivasa <gurupras@buffalo.edu>
Co-authored-by: Stephane Fortin Bouchard <stephane.f.bouchard@gmail.com>
Co-authored-by: Zev Averbach <zev@averba.ch>
Co-authored-by: Vincent Orback <hello@vincentorback.se>
Co-authored-by: trafium <trafium@gmail.com>
Co-authored-by: xansen <27698939+xansen@users.noreply.github.com>
Co-authored-by: zoomerdev <59863739+zoomerdev@users.noreply.github.com>
Co-authored-by: Mikaël Castellani <mikael.castellani@gmail.com>
Co-authored-by: dirkjf <d.j.faber@outlook.com>
2020-11-14 13:24:11 +11:00
Sam Potts 5d2c288721 Merge pull request #1961 from Benny739/master
fixed #1181 vimeo oembed api
2020-10-19 22:41:09 +11:00
Sam Potts 30989e4dbc Merge pull request #1982 from tbntdima/feat/fix-fulscreen-type
fix(plyr.d.ts): add force to FullScreenOptions
2020-10-15 09:09:49 +11:00
Dima An 967206c695 fix(plyr.d.ts): add force to FullScreenOptions 2020-10-14 17:09:14 +02:00
Benny739 e646207ed6 vimeo oembed api 2020-09-23 01:24:11 +02:00
Sam Potts 98dbb2e43f Merge pull request #1885 from mercuryseries/patch-1
Fix small typo
2020-08-30 15:52:19 +10:00
Sam Potts 3e70f32555 Merge pull request #1904 from sampotts/dependabot/npm_and_yarn/lodash-4.17.19
Bump lodash from 4.17.15 to 4.17.19
2020-08-30 15:47:00 +10:00
Sam Potts 80fbeeb415 Merge pull request #1920 from Kithaitaa/Kithaitaa-patch-2
Please add our website to the "Used by" list
2020-08-30 15:46:11 +10:00
Sam Potts 8261ebd502 Merge pull request #1928 from ethanve/patch-1
fix: blankVideo type
2020-08-30 15:45:57 +10:00
Ethan Veres 6f77e21e51 chore: fix blankVideo types 2020-08-12 10:11:45 -04:00
Kith 7910fea011 Please add our website to the "Used by" list
I would be happy if you could add our website to the "used by" list. We are a video game magazine that has been using Plyr for some time now for. Thx in advance.

Besides that i send you a donation through PayPal a few days ago =)
2020-08-05 10:44:41 +02:00
dependabot[bot] 8e0cde2949 Bump lodash from 4.17.15 to 4.17.19
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.15 to 4.17.19.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.15...4.17.19)

Signed-off-by: dependabot[bot] <support@github.com>
2020-07-16 18:00:08 +00:00
Sam Potts 391afe2814 Merge pull request #1889 from rutheneum-bote/patch-1
Add us to the "Used by" list
2020-06-30 22:08:25 +10:00
Rutheneum-Bote 68e3944bb8 Add us to the "Used by" list
We're the students' newspaper of the Goethe Grammar School/Rutheneum since 1608 and we use Plyr in order to present the students' songs that were submitted to our school's creativity contest.
2020-06-30 11:47:09 +00:00
Honoré Hounwanou 2ee6ae16b2 Fix small typo
Add missing "d" in video.
2020-06-27 10:18:49 -04:00
Sam Potts ef85cb6195 Merge pull request #1822 from zoomerdev/patch-1
Add BitChute to users list
2020-05-05 15:26:29 +10:00
zoomerdev dc8612fcd0 add BitChute to users list 2020-05-05 01:19:42 -04:00
58 changed files with 3472 additions and 1916 deletions
+16 -28
View File
@@ -1,30 +1,18 @@
{
"parser": "babel-eslint",
"extends": ["airbnb-base", "prettier"],
"plugins": ["simple-import-sort", "import"],
"env": {
"browser": true,
"es6": true
},
"globals": {
"Plyr": false,
"jQuery": false
},
"rules": {
"import/no-cycle": "warn",
"padding-line-between-statements": [
"error",
{
"blankLine": "never",
"prev": ["singleline-const", "singleline-let", "singleline-var"],
"next": ["singleline-const", "singleline-let", "singleline-var"]
}
],
"sort-imports": "off",
"import/order": "off",
"simple-import-sort/sort": "error"
},
"parserOptions": {
"sourceType": "module"
}
"parser": "babel-eslint",
"extends": ["@sampotts/eslint-config/es6"],
"env": {
"browser": true,
"es6": true
},
"globals": {
"Plyr": false,
"jQuery": false
},
"rules": {
"import/no-cycle": "warn"
},
"parserOptions": {
"sourceType": "module"
}
}
+15
View File
@@ -1,3 +1,18 @@
### v3.6.3
- Fix volume when unmuting from volume 0 using YouTube (thanks @stephanefbouchard)
- Add missing unit to calc in media query (thanks @vincentorback)
- Assigning player's lastSeekTime on rewind/fast forward to prevent immediate controls hide on mobile (thanks @trafium)
- Fix for volume control overflowing in Firefox (thanks @dirkjf)
- Force fullscreen events to trigger on plyr element (media element in iOS) and not fullscreen container (thanks @theprojectsomething)
- TypeScript types improvements (thanks @akuma06 & @iwatakeshi)
- Dash demo link fixed (thanks @jonathanarbely)
- Fix "A `ReferenceError: _classCallCheck is not defined` error has occurred." error (thanks @hex-ci)
- Fix issue with CSS custom property check (thanks @syedhusain-appspace)
- Fix for slow loading videos not autoplaying (thanks @DanielHuntleySBG)
- Fix for betwork requests are not cancelled after the player is destroyed (thanks @DanielHuntleySBG)
- Added option to disable custom controls for YouTube and Vimeo
### v3.6.2
- Fixes for CSS Custom Property related errors in some build tools (thanks @Bashev)
+11 -6
View File
@@ -31,7 +31,7 @@ Plyr is a simple, lightweight, accessible and customizable HTML5, YouTube and Vi
### Demos
You can try Plyr in Codepen using our minimal templates: [HTML5 video](https://codepen.io/pen?template=bKeqpr), [HTML5 audio](https://codepen.io/pen?template=rKLywR), [YouTube](https://codepen.io/pen?template=GGqbbJ), [Vimeo](https://codepen.io/pen?template=bKeXNq). For Streaming we also have example integrations with: [Dash.js](https://codepen.io/pen?template=zaBgBy), [Hls.js](https://codepen.io/pen?template=oyLKQb) and [Shaka Player](https://codepen.io/pen?template=ZRpzZO)
You can try Plyr in Codepen using our minimal templates: [HTML5 video](https://codepen.io/pen?template=bKeqpr), [HTML5 audio](https://codepen.io/pen?template=rKLywR), [YouTube](https://codepen.io/pen?template=GGqbbJ), [Vimeo](https://codepen.io/pen?template=bKeXNq). For Streaming we also have example integrations with: [Dash.js](https://codepen.io/pen?template=GRoogML), [Hls.js](https://codepen.io/pen?template=oyLKQb) and [Shaka Player](https://codepen.io/pen?template=ZRpzZO)
# Quick setup
@@ -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.
```html
<script src="https://cdn.plyr.io/3.6.2/plyr.js"></script>
<script src="https://cdn.plyr.io/3.6.3/plyr.js"></script>
```
...or...
```html
<script src="https://cdn.plyr.io/3.6.2/plyr.polyfilled.js"></script>
<script src="https://cdn.plyr.io/3.6.3/plyr.polyfilled.js"></script>
```
## 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:
```html
<link rel="stylesheet" href="https://cdn.plyr.io/3.6.2/plyr.css" />
<link rel="stylesheet" href="https://cdn.plyr.io/3.6.3/plyr.css" />
```
## 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
reference, the CDN hosted SVG sprite can be found at `https://cdn.plyr.io/3.6.2/plyr.svg`.
reference, the CDN hosted SVG sprite can be found at `https://cdn.plyr.io/3.6.3/plyr.svg`.
# Ads
@@ -268,7 +268,7 @@ You can set them in your CSS for all players:
```html
<video class="player" style="--plyr-color-main: #1ac266;">
...
</vieo>
</video>
```
### SASS
@@ -790,6 +790,7 @@ Some awesome folks have made plugins for CMSs and Components for JavaScript fram
| Neos | Jon Uhlmann ([@jonnitto](https://github.com/jonnitto)) | [https://packagist.org/packages/jonnitto/plyr](https://packagist.org/packages/jonnitto/plyr) |
| Kirby | Dominik Pschenitschni ([@dpschen](https://github.com/dpschen)) | [https://github.com/dpschen/kirby-plyrtag](https://github.com/dpschen/kirby-plyrtag) |
| REDAXO | FriendsOfRedaxo / skerbis ([@skerbis](https://friendsofredaxo.github.io)) | [https://github.com/FriendsOfREDAXO/plyr](https://github.com/FriendsOfREDAXO/plyr) |
| svelte-plyr | Ben Woodward / benwoodward ([@benwoodward](https://github.com/benwoodward)) | [https://github.com/benwoodward](https://github.com/benwoodward) |
# Issues
@@ -833,6 +834,10 @@ Plyr costs money to run, not only my time. I donate my time for free as I enjoy
- [Oscar Radio](http://oscar-radio.xyz/)
- [Sparkk TV](https://www.sparkktv.com/)
- [@halfhalftravel](https://www.halfhalftravel.com/)
- [BitChute](https://www.bitchute.com)
- [Rutheneum-Bote](https://gymnasium-rutheneum.de/content/newspaper/kreativwettbewerb.php)
- [pressakey.com | Blog-Magazin für Videospiele](https://pressakey.com)
- [STROLLÿN: Work with a View](https://strollyn.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 😎
+1 -1
View File
File diff suppressed because one or more lines are too long
+218 -148
View File
@@ -14463,7 +14463,7 @@ typeof navigator === "object" && (function () {
check$1(typeof self == 'object' && self) ||
check$1(typeof commonjsGlobal == 'object' && commonjsGlobal) ||
// eslint-disable-next-line no-new-func
Function('return this')();
(function () { return this; })() || Function('return this')();
var fails$1 = function (exec) {
try {
@@ -14658,7 +14658,7 @@ typeof navigator === "object" && (function () {
(module.exports = function (key, value) {
return sharedStore$1[key] || (sharedStore$1[key] = value !== undefined ? value : {});
})('versions', []).push({
version: '3.6.5',
version: '3.7.0',
mode: 'global',
copyright: '© 2020 Denis Pushkarev (zloirock.ru)'
});
@@ -14696,11 +14696,12 @@ typeof navigator === "object" && (function () {
};
if (nativeWeakMap$1) {
var store$3 = new WeakMap$4();
var store$3 = sharedStore$1.state || (sharedStore$1.state = new WeakMap$4());
var wmget$1 = store$3.get;
var wmhas$1 = store$3.has;
var wmset$1 = store$3.set;
set$3 = function (it, metadata) {
metadata.facade = it;
wmset$1.call(store$3, it, metadata);
return metadata;
};
@@ -14714,6 +14715,7 @@ typeof navigator === "object" && (function () {
var STATE$1 = sharedKey$1('state');
hiddenKeys$2[STATE$1] = true;
set$3 = function (it, metadata) {
metadata.facade = it;
createNonEnumerableProperty$1(it, STATE$1, metadata);
return metadata;
};
@@ -14742,9 +14744,15 @@ typeof navigator === "object" && (function () {
var unsafe = options ? !!options.unsafe : false;
var simple = options ? !!options.enumerable : false;
var noTargetGet = options ? !!options.noTargetGet : false;
var state;
if (typeof value == 'function') {
if (typeof key == 'string' && !has$2(value, 'name')) createNonEnumerableProperty$1(value, 'name', key);
enforceInternalState(value).source = TEMPLATE.join(typeof key == 'string' ? key : '');
if (typeof key == 'string' && !has$2(value, 'name')) {
createNonEnumerableProperty$1(value, 'name', key);
}
state = enforceInternalState(value);
if (!state.source) {
state.source = TEMPLATE.join(typeof key == 'string' ? key : '');
}
}
if (O === global_1$1) {
if (simple) O[key] = value;
@@ -15370,14 +15378,20 @@ typeof navigator === "object" && (function () {
// https://tc39.github.io/ecma262/#sec-array.prototype-@@unscopables
addToUnscopables$1(FIND$1);
var iteratorClose = function (iterator) {
var returnMethod = iterator['return'];
if (returnMethod !== undefined) {
return anObject$1(returnMethod.call(iterator)).value;
}
};
// call something on iterator step with safe closing on error
var callWithSafeIterationClosing$1 = function (iterator, fn, value, ENTRIES) {
try {
return ENTRIES ? fn(anObject$1(value)[0], value[1]) : fn(value);
// 7.4.6 IteratorClose(iterator, completion)
} catch (error) {
var returnMethod = iterator['return'];
if (returnMethod !== undefined) anObject$1(returnMethod.call(iterator));
iteratorClose(iterator);
throw error;
}
};
@@ -16098,11 +16112,11 @@ typeof navigator === "object" && (function () {
var regexp = /./;
try {
'/./'[METHOD_NAME](regexp);
} catch (e) {
} catch (error1) {
try {
regexp[MATCH$4] = false;
return '/./'[METHOD_NAME](regexp);
} catch (f) { /* empty */ }
} catch (error2) { /* empty */ }
} return false;
};
@@ -16422,16 +16436,31 @@ typeof navigator === "object" && (function () {
var internalMetadata_3$1 = internalMetadata$1.getWeakData;
var internalMetadata_4$1 = internalMetadata$1.onFreeze;
var iterate_1$1 = createCommonjsModule(function (module) {
var Result = function (stopped, result) {
this.stopped = stopped;
this.result = result;
};
var iterate = module.exports = function (iterable, fn, that, AS_ENTRIES, IS_ITERATOR) {
var boundFunction = functionBindContext$1(fn, that, AS_ENTRIES ? 2 : 1);
var iterate = function (iterable, unboundFunction, options) {
var that = options && options.that;
var AS_ENTRIES = !!(options && options.AS_ENTRIES);
var IS_ITERATOR = !!(options && options.IS_ITERATOR);
var INTERRUPTED = !!(options && options.INTERRUPTED);
var fn = functionBindContext$1(unboundFunction, that, 1 + AS_ENTRIES + INTERRUPTED);
var iterator, iterFn, index, length, result, next, step;
var stop = function (condition) {
if (iterator) iteratorClose(iterator);
return new Result(true, condition);
};
var callFn = function (value) {
if (AS_ENTRIES) {
anObject$1(value);
return INTERRUPTED ? fn(value[0], value[1], stop) : fn(value[0], value[1]);
} return INTERRUPTED ? fn(value, stop) : fn(value);
};
if (IS_ITERATOR) {
iterator = iterable;
} else {
@@ -16440,9 +16469,7 @@ typeof navigator === "object" && (function () {
// optimisation for array iterators
if (isArrayIteratorMethod$1(iterFn)) {
for (index = 0, length = toLength$1(iterable.length); length > index; index++) {
result = AS_ENTRIES
? boundFunction(anObject$1(step = iterable[index])[0], step[1])
: boundFunction(iterable[index]);
result = callFn(iterable[index]);
if (result && result instanceof Result) return result;
} return new Result(false);
}
@@ -16451,16 +16478,16 @@ typeof navigator === "object" && (function () {
next = iterator.next;
while (!(step = next.call(iterator)).done) {
result = callWithSafeIterationClosing$1(iterator, boundFunction, step.value, AS_ENTRIES);
try {
result = callFn(step.value);
} catch (error) {
iteratorClose(iterator);
throw error;
}
if (typeof result == 'object' && result && result instanceof Result) return result;
} return new Result(false);
};
iterate.stop = function (result) {
return new Result(true, result);
};
});
var anInstance$1 = function (it, Constructor, name) {
if (!(it instanceof Constructor)) {
throw TypeError('Incorrect ' + (name ? name + ' ' : '') + 'invocation');
@@ -16524,7 +16551,7 @@ typeof navigator === "object" && (function () {
Constructor = wrapper(function (dummy, iterable) {
anInstance$1(dummy, Constructor, CONSTRUCTOR_NAME);
var that = inheritIfRequired$1(new NativeConstructor(), dummy, Constructor);
if (iterable != undefined) iterate_1$1(iterable, that[ADDER], that, IS_MAP);
if (iterable != undefined) iterate(iterable, that[ADDER], { that: that, AS_ENTRIES: IS_MAP });
return that;
});
Constructor.prototype = NativePrototype;
@@ -16614,7 +16641,7 @@ typeof navigator === "object" && (function () {
id: id$3++,
frozen: undefined
});
if (iterable != undefined) iterate_1$1(iterable, that[ADDER], that, IS_MAP);
if (iterable != undefined) iterate(iterable, that[ADDER], { that: that, AS_ENTRIES: IS_MAP });
});
var getInternalState = internalStateGetterFor$1(CONSTRUCTOR_NAME);
@@ -17452,7 +17479,7 @@ typeof navigator === "object" && (function () {
var URLSearchParamsPrototype$1 = URLSearchParamsConstructor$1.prototype;
redefineAll$1(URLSearchParamsPrototype$1, {
// `URLSearchParams.prototype.appent` method
// `URLSearchParams.prototype.append` method
// https://url.spec.whatwg.org/#dom-urlsearchparams-append
append: function append(name, value) {
validateArgumentsLength$1(arguments.length, 2);
@@ -19605,6 +19632,8 @@ typeof navigator === "object" && (function () {
var engineIsIos$1 = /(iphone|ipod|ipad).*applewebkit/i.test(engineUserAgent$1);
var engineIsNode = classofRaw$1(global_1$1.process) == 'process';
var location$1 = global_1$1.location;
var set$4 = global_1$1.setImmediate;
var clear$1 = global_1$1.clearImmediate;
@@ -19657,7 +19686,7 @@ typeof navigator === "object" && (function () {
delete queue$1[id];
};
// Node.js 0.8-
if (classofRaw$1(process$6) == 'process') {
if (engineIsNode) {
defer$1 = function (id) {
process$6.nextTick(runner$1(id));
};
@@ -19679,8 +19708,8 @@ typeof navigator === "object" && (function () {
global_1$1.addEventListener &&
typeof postMessage == 'function' &&
!global_1$1.importScripts &&
!fails$1(post$1) &&
location$1.protocol !== 'file:'
location$1 && location$1.protocol !== 'file:' &&
!fails$1(post$1)
) {
defer$1 = post$1;
global_1$1.addEventListener('message', listener$1, false);
@@ -19706,14 +19735,14 @@ typeof navigator === "object" && (function () {
};
var getOwnPropertyDescriptor$7 = objectGetOwnPropertyDescriptor$1.f;
var macrotask$1 = task$2.set;
var MutationObserver$2 = global_1$1.MutationObserver || global_1$1.WebKitMutationObserver;
var document$4 = global_1$1.document;
var process$7 = global_1$1.process;
var Promise$2 = global_1$1.Promise;
var IS_NODE$2 = classofRaw$1(process$7) == 'process';
// Node.js 11 shows ExperimentalWarning on getting `queueMicrotask`
var queueMicrotaskDescriptor$1 = getOwnPropertyDescriptor$7(global_1$1, 'queueMicrotask');
var queueMicrotask$1 = queueMicrotaskDescriptor$1 && queueMicrotaskDescriptor$1.value;
@@ -19724,7 +19753,7 @@ typeof navigator === "object" && (function () {
if (!queueMicrotask$1) {
flush$1 = function () {
var parent, fn;
if (IS_NODE$2 && (parent = process$7.domain)) parent.exit();
if (engineIsNode && (parent = process$7.domain)) parent.exit();
while (head$1) {
fn = head$1.fn;
head$1 = head$1.next;
@@ -19739,15 +19768,10 @@ typeof navigator === "object" && (function () {
if (parent) parent.enter();
};
// Node.js
if (IS_NODE$2) {
notify$2 = function () {
process$7.nextTick(flush$1);
};
// browsers with MutationObserver, except iOS - https://github.com/zloirock/core-js/issues/339
} else if (MutationObserver$2 && !engineIsIos$1) {
if (!engineIsIos$1 && !engineIsNode && MutationObserver$2 && document$4) {
toggle$1 = true;
node$1 = document.createTextNode('');
node$1 = document$4.createTextNode('');
new MutationObserver$2(flush$1).observe(node$1, { characterData: true });
notify$2 = function () {
node$1.data = toggle$1 = !toggle$1;
@@ -19760,6 +19784,11 @@ typeof navigator === "object" && (function () {
notify$2 = function () {
then$1.call(promise$1, flush$1);
};
// Node.js without promises
} else if (engineIsNode) {
notify$2 = function () {
process$7.nextTick(flush$1);
};
// for other environments - macrotask based on:
// - setImmediate
// - MessageChannel
@@ -19838,6 +19867,7 @@ typeof navigator === "object" && (function () {
var SPECIES$c = wellKnownSymbol$1('species');
var PROMISE$1 = 'Promise';
var getInternalState$8 = internalState$1.get;
@@ -19845,13 +19875,13 @@ typeof navigator === "object" && (function () {
var getInternalPromiseState$1 = internalState$1.getterFor(PROMISE$1);
var PromiseConstructor$1 = nativePromiseConstructor$1;
var TypeError$2 = global_1$1.TypeError;
var document$4 = global_1$1.document;
var document$5 = global_1$1.document;
var process$8 = global_1$1.process;
var $fetch$3 = getBuiltIn$1('fetch');
var newPromiseCapability$3 = newPromiseCapability$2.f;
var newGenericPromiseCapability$1 = newPromiseCapability$3;
var IS_NODE$3 = classofRaw$1(process$8) == 'process';
var DISPATCH_EVENT$1 = !!(document$4 && document$4.createEvent && global_1$1.dispatchEvent);
var DISPATCH_EVENT$1 = !!(document$5 && document$5.createEvent && global_1$1.dispatchEvent);
var NATIVE_REJECTION_EVENT = typeof PromiseRejectionEvent == 'function';
var UNHANDLED_REJECTION$1 = 'unhandledrejection';
var REJECTION_HANDLED$1 = 'rejectionhandled';
var PENDING$1 = 0;
@@ -19869,7 +19899,7 @@ typeof navigator === "object" && (function () {
// We can't detect it synchronously, so just check versions
if (engineV8Version$1 === 66) return true;
// Unhandled rejections tracking support, NodeJS Promise without it fails @@species test
if (!IS_NODE$3 && typeof PromiseRejectionEvent != 'function') return true;
if (!engineIsNode && !NATIVE_REJECTION_EVENT) return true;
}
// We can't use @@species feature detection in V8 since it causes
// deoptimization and performance degradation
@@ -19895,7 +19925,7 @@ typeof navigator === "object" && (function () {
return isObject$2(it) && typeof (then = it.then) == 'function' ? then : false;
};
var notify$3 = function (promise, state, isReject) {
var notify$3 = function (state, isReject) {
if (state.notified) return;
state.notified = true;
var chain = state.reactions;
@@ -19914,7 +19944,7 @@ typeof navigator === "object" && (function () {
try {
if (handler) {
if (!ok) {
if (state.rejection === UNHANDLED$1) onHandleUnhandled$1(promise, state);
if (state.rejection === UNHANDLED$1) onHandleUnhandled$1(state);
state.rejection = HANDLED$1;
}
if (handler === true) result = value;
@@ -19939,36 +19969,37 @@ typeof navigator === "object" && (function () {
}
state.reactions = [];
state.notified = false;
if (isReject && !state.rejection) onUnhandled$1(promise, state);
if (isReject && !state.rejection) onUnhandled$1(state);
});
};
var dispatchEvent$1 = function (name, promise, reason) {
var event, handler;
if (DISPATCH_EVENT$1) {
event = document$4.createEvent('Event');
event = document$5.createEvent('Event');
event.promise = promise;
event.reason = reason;
event.initEvent(name, false, true);
global_1$1.dispatchEvent(event);
} else event = { promise: promise, reason: reason };
if (handler = global_1$1['on' + name]) handler(event);
if (!NATIVE_REJECTION_EVENT && (handler = global_1$1['on' + name])) handler(event);
else if (name === UNHANDLED_REJECTION$1) hostReportErrors$1('Unhandled promise rejection', reason);
};
var onUnhandled$1 = function (promise, state) {
var onUnhandled$1 = function (state) {
task$3.call(global_1$1, function () {
var promise = state.facade;
var value = state.value;
var IS_UNHANDLED = isUnhandled$1(state);
var result;
if (IS_UNHANDLED) {
result = perform$1(function () {
if (IS_NODE$3) {
if (engineIsNode) {
process$8.emit('unhandledRejection', value, promise);
} else dispatchEvent$1(UNHANDLED_REJECTION$1, promise, value);
});
// Browsers should not trigger `rejectionHandled` event if it was handled here, NodeJS - should
state.rejection = IS_NODE$3 || isUnhandled$1(state) ? UNHANDLED$1 : HANDLED$1;
state.rejection = engineIsNode || isUnhandled$1(state) ? UNHANDLED$1 : HANDLED$1;
if (result.error) throw result.value;
}
});
@@ -19978,55 +20009,56 @@ typeof navigator === "object" && (function () {
return state.rejection !== HANDLED$1 && !state.parent;
};
var onHandleUnhandled$1 = function (promise, state) {
var onHandleUnhandled$1 = function (state) {
task$3.call(global_1$1, function () {
if (IS_NODE$3) {
var promise = state.facade;
if (engineIsNode) {
process$8.emit('rejectionHandled', promise);
} else dispatchEvent$1(REJECTION_HANDLED$1, promise, state.value);
});
};
var bind$1 = function (fn, promise, state, unwrap) {
var bind$1 = function (fn, state, unwrap) {
return function (value) {
fn(promise, state, value, unwrap);
fn(state, value, unwrap);
};
};
var internalReject$1 = function (promise, state, value, unwrap) {
var internalReject$1 = function (state, value, unwrap) {
if (state.done) return;
state.done = true;
if (unwrap) state = unwrap;
state.value = value;
state.state = REJECTED$1;
notify$3(promise, state, true);
notify$3(state, true);
};
var internalResolve$1 = function (promise, state, value, unwrap) {
var internalResolve$1 = function (state, value, unwrap) {
if (state.done) return;
state.done = true;
if (unwrap) state = unwrap;
try {
if (promise === value) throw TypeError$2("Promise can't be resolved itself");
if (state.facade === value) throw TypeError$2("Promise can't be resolved itself");
var then = isThenable$2(value);
if (then) {
microtask$1(function () {
var wrapper = { done: false };
try {
then.call(value,
bind$1(internalResolve$1, promise, wrapper, state),
bind$1(internalReject$1, promise, wrapper, state)
bind$1(internalResolve$1, wrapper, state),
bind$1(internalReject$1, wrapper, state)
);
} catch (error) {
internalReject$1(promise, wrapper, error, state);
internalReject$1(wrapper, error, state);
}
});
} else {
state.value = value;
state.state = FULFILLED$1;
notify$3(promise, state, false);
notify$3(state, false);
}
} catch (error) {
internalReject$1(promise, { done: false }, error, state);
internalReject$1({ done: false }, error, state);
}
};
@@ -20039,9 +20071,9 @@ typeof navigator === "object" && (function () {
Internal$1.call(this);
var state = getInternalState$8(this);
try {
executor(bind$1(internalResolve$1, this, state), bind$1(internalReject$1, this, state));
executor(bind$1(internalResolve$1, state), bind$1(internalReject$1, state));
} catch (error) {
internalReject$1(this, state, error);
internalReject$1(state, error);
}
};
// eslint-disable-next-line no-unused-vars
@@ -20065,10 +20097,10 @@ typeof navigator === "object" && (function () {
var reaction = newPromiseCapability$3(speciesConstructor$1(this, PromiseConstructor$1));
reaction.ok = typeof onFulfilled == 'function' ? onFulfilled : true;
reaction.fail = typeof onRejected == 'function' && onRejected;
reaction.domain = IS_NODE$3 ? process$8.domain : undefined;
reaction.domain = engineIsNode ? process$8.domain : undefined;
state.parent = true;
state.reactions.push(reaction);
if (state.state != PENDING$1) notify$3(this, state, false);
if (state.state != PENDING$1) notify$3(state, false);
return reaction.promise;
},
// `Promise.prototype.catch` method
@@ -20081,8 +20113,8 @@ typeof navigator === "object" && (function () {
var promise = new Internal$1();
var state = getInternalState$8(promise);
this.promise = promise;
this.resolve = bind$1(internalResolve$1, promise, state);
this.reject = bind$1(internalReject$1, promise, state);
this.resolve = bind$1(internalResolve$1, state);
this.reject = bind$1(internalReject$1, state);
};
newPromiseCapability$2.f = newPromiseCapability$3 = function (C) {
return C === PromiseConstructor$1 || C === PromiseWrapper$1
@@ -20153,7 +20185,7 @@ typeof navigator === "object" && (function () {
var values = [];
var counter = 0;
var remaining = 1;
iterate_1$1(iterable, function (promise) {
iterate(iterable, function (promise) {
var index = counter++;
var alreadyCalled = false;
values.push(undefined);
@@ -20178,7 +20210,7 @@ typeof navigator === "object" && (function () {
var reject = capability.reject;
var result = perform$1(function () {
var $promiseResolve = aFunction$3(C.resolve);
iterate_1$1(iterable, function (promise) {
iterate(iterable, function (promise) {
$promiseResolve.call(C, promise).then(capability.resolve, reject);
});
});
@@ -20425,12 +20457,17 @@ typeof navigator === "object" && (function () {
var STRICT_METHOD$a = arrayMethodIsStrict$1('reduce');
var USES_TO_LENGTH$i = arrayMethodUsesToLength$1('reduce', { 1: 0 });
// Chrome 80-82 has a critical bug
// https://bugs.chromium.org/p/chromium/issues/detail?id=1049982
var CHROME_BUG = !engineIsNode && engineV8Version$1 > 79 && engineV8Version$1 < 83;
// `Array.prototype.reduce` method
// https://tc39.github.io/ecma262/#sec-array.prototype.reduce
_export$1({ target: 'Array', proto: true, forced: !STRICT_METHOD$a || !USES_TO_LENGTH$i }, {
_export$1({ target: 'Array', proto: true, forced: !STRICT_METHOD$a || !USES_TO_LENGTH$i || CHROME_BUG }, {
reduce: function reduce(callbackfn /* , initialValue */) {
return $reduce$1(this, callbackfn, arguments.length, arguments.length > 1 ? arguments[1] : undefined);
}
@@ -21064,7 +21101,12 @@ typeof navigator === "object" && (function () {
if (this.isVimeo && !this.config.vimeo.premium && this.supported.ui) {
var height = 100 / this.media.offsetWidth * parseInt(window.getComputedStyle(this.media).paddingBottom, 10);
var offset = (height - padding) / (height / 50);
this.media.style.transform = "translateY(-".concat(offset, "%)");
if (this.fullscreen.active) {
wrapper.style.paddingBottom = null;
} else {
this.media.style.transform = "translateY(-".concat(offset, "%)");
}
} else if (this.isHTML5) {
wrapper.classList.toggle(this.config.classNames.videoFixedRatio, ratio !== null);
}
@@ -23644,7 +23686,7 @@ typeof navigator === "object" && (function () {
// Sprite (for icons)
loadSprite: true,
iconPrefix: 'plyr',
iconUrl: 'https://cdn.plyr.io/3.6.2/plyr.svg',
iconUrl: 'https://cdn.plyr.io/3.6.3/plyr.svg',
// Blank video (used to prevent errors on source change)
blankVideo: 'https://cdn.plyr.io/static/blank.mp4',
// Quality default
@@ -23762,7 +23804,7 @@ typeof navigator === "object" && (function () {
vimeo: {
sdk: 'https://player.vimeo.com/api/player.js',
iframe: 'https://player.vimeo.com/video/{0}?{1}',
api: 'https://vimeo.com/api/v2/video/{0}.json'
api: 'https://vimeo.com/api/oembed.json?url={0}'
},
youtube: {
sdk: 'https://www.youtube.com/iframe_api',
@@ -23932,24 +23974,27 @@ typeof navigator === "object" && (function () {
title: false,
speed: true,
transparent: false,
// Custom settings from Plyr
customControls: true,
referrerPolicy: null,
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/referrerPolicy
// Whether the owner of the video has a Pro or Business account
// (which allows us to properly hide controls without CSS hacks, etc)
premium: false,
// Custom settings from Plyr
referrerPolicy: null // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/referrerPolicy
premium: false
},
// YouTube plugin
youtube: {
noCookie: true,
// Whether to use an alternative version of YouTube without cookies
rel: 0,
// No related vids
showinfo: 0,
// Hide info
iv_load_policy: 3,
// Hide annotations
modestbranding: 1 // Hide logos as much as possible (they still show one in the corner when paused)
modestbranding: 1,
// Hide logos as much as possible (they still show one in the corner when paused)
// Custom settings from Plyr
customControls: true,
noCookie: false // Whether to use an alternative version of YouTube without cookies
}
};
@@ -24068,7 +24113,7 @@ typeof navigator === "object" && (function () {
return;
}
_this.toggle();
_this.player.listeners.proxy(event, _this.toggle, 'fullscreen');
}); // Tap focus when in fullscreen
on.call(this, this.player.elements.container, 'keydown', function (event) {
@@ -24091,10 +24136,12 @@ typeof navigator === "object" && (function () {
if (is$2.element(button)) {
button.pressed = this.active;
} // Trigger an event
} // Always trigger events on the plyr / media element (not a fullscreen container) and let them bubble up
triggerEvent.call(this.player, this.target, this.active ? 'enterfullscreen' : 'exitfullscreen', true);
var target = this.target === this.player.media ? this.target : this.player.elements.container; // Trigger an event
triggerEvent.call(this.player, target, this.active ? 'enterfullscreen' : 'exitfullscreen', true);
}
}, {
key: "toggleFallback",
@@ -24489,7 +24536,9 @@ typeof navigator === "object" && (function () {
} // Set property synchronously to respect the call order
this.media.setAttribute('data-poster', poster); // Wait until ui is ready
this.media.setAttribute('data-poster', poster); // Show the poster
this.elements.poster.removeAttribute('hidden'); // Wait until ui is ready
return ready.call(this) // Load image
.then(function () {
@@ -24573,7 +24622,7 @@ typeof navigator === "object" && (function () {
// Loop through values (as they are the keys when the object is spread 🤔)
Object.values(_objectSpread2({}, this.media.style)) // We're only fussed about Plyr specific properties
.filter(function (key) {
return !is$2.empty(key) && key.startsWith('--plyr');
return !is$2.empty(key) && is$2.string(key) && key.startsWith('--plyr');
}).forEach(function (key) {
// Set on the container
_this5.elements.container.style.setProperty(key, _this5.media.style.getPropertyValue(key)); // Clean up from media element
@@ -24921,7 +24970,14 @@ typeof navigator === "object" && (function () {
ratio = _setPlayerSize.ratio; // Set Vimeo gutter
setGutter(ratio, padding, isEnter); // If not using native browser fullscreen API, we need to check for resizes of viewport
setGutter(ratio, padding, isEnter); // Horrible hack for Safari 14 not repainting properly on entering fullscreen
if (isEnter) {
setTimeout(function () {
return repaint(elements.container);
}, 100);
} // If not using native browser fullscreen API, we need to check for resizes of viewport
if (!usingNative) {
if (isEnter) {
@@ -25112,9 +25168,17 @@ typeof navigator === "object" && (function () {
this.bind(elements.buttons.restart, 'click', player.restart, 'restart'); // Rewind
this.bind(elements.buttons.rewind, 'click', player.rewind, 'rewind'); // Rewind
this.bind(elements.buttons.rewind, 'click', function () {
// Record seek time so we can prevent hiding controls for a few seconds after rewind
player.lastSeekTime = Date.now();
player.rewind();
}, 'rewind'); // Rewind
this.bind(elements.buttons.fastForward, 'click', player.forward, 'fastForward'); // Mute toggle
this.bind(elements.buttons.fastForward, 'click', function () {
// Record seek time so we can prevent hiding controls for a few seconds after fast forward
player.lastSeekTime = Date.now();
player.forward();
}, 'fastForward'); // Mute toggle
this.bind(elements.buttons.mute, 'click', function () {
player.muted = !player.muted;
@@ -25822,35 +25886,32 @@ typeof navigator === "object" && (function () {
} // Inject the package
var poster = player.poster;
if (premium) {
iframe.setAttribute('data-poster', poster);
if (premium || !config.customControls) {
iframe.setAttribute('data-poster', player.poster);
player.media = replaceElement(iframe, player.media);
} else {
var wrapper = createElement$1('div', {
class: player.config.classNames.embedContainer,
'data-poster': poster
'data-poster': player.poster
});
wrapper.appendChild(iframe);
player.media = replaceElement(wrapper, player.media);
} // Get poster image
fetch(format(player.config.urls.vimeo.api, id), 'json').then(function (response) {
if (is$2.empty(response)) {
return;
} // Get the URL for thumbnail
if (!config.customControls) {
fetch(format(player.config.urls.vimeo.api, src)).then(function (response) {
if (is$2.empty(response) || !response.thumbnail_url) {
return;
} // Set and show poster
var url = new URL(response[0].thumbnail_large); // Get original image
url.pathname = "".concat(url.pathname.split('_')[0], ".jpg"); // Set and show poster
ui.setPoster.call(player, url.href).catch(function () {});
}); // Setup instance
ui.setPoster.call(player, response.thumbnail_url).catch(function () {});
});
} // Setup instance
// https://github.com/vimeo/player.js
player.embed = new window.Vimeo.Player(iframe, {
autopause: player.config.autopause,
muted: player.muted
@@ -26090,9 +26151,11 @@ typeof navigator === "object" && (function () {
triggerEvent.call(player, player.media, 'error');
}); // Rebuild UI
setTimeout(function () {
return ui.build.call(player);
}, 0);
if (config.customControls) {
setTimeout(function () {
return ui.build.call(player);
}, 0);
}
}
};
@@ -26183,7 +26246,8 @@ typeof navigator === "object" && (function () {
},
// API ready
ready: function ready() {
var player = this; // Ignore already setup (race condition)
var player = this;
var config = player.config.youtube; // Ignore already setup (race condition)
var currentId = player.media && player.media.getAttribute('id');
@@ -26200,53 +26264,53 @@ typeof navigator === "object" && (function () {
var videoId = parseId$1(source);
var id = generateId(player.provider); // Get poster, if already set
var poster = player.poster; // Replace media element
var id = generateId(player.provider); // Replace media element
var container = createElement$1('div', {
id: id,
'data-poster': poster
'data-poster': config.customControls ? player.poster : undefined
});
player.media = replaceElement(container, player.media); // Id to poster wrapper
player.media = replaceElement(container, player.media); // Only load the poster when using custom controls
var posterSrc = function posterSrc(s) {
return "https://i.ytimg.com/vi/".concat(videoId, "/").concat(s, "default.jpg");
}; // Check thumbnail images in order of quality, but reject fallback thumbnails (120px wide)
if (config.customControls) {
var posterSrc = function posterSrc(s) {
return "https://i.ytimg.com/vi/".concat(videoId, "/").concat(s, "default.jpg");
}; // Check thumbnail images in order of quality, but reject fallback thumbnails (120px wide)
loadImage(posterSrc('maxres'), 121) // Higest quality and unpadded
.catch(function () {
return loadImage(posterSrc('sd'), 121);
}) // 480p padded 4:3
.catch(function () {
return loadImage(posterSrc('hq'));
}) // 360p padded 4:3. Always exists
.then(function (image) {
return ui.setPoster.call(player, image.src);
}).then(function (src) {
// If the image is padded, use background-size "cover" instead (like youtube does too with their posters)
if (!src.includes('maxres')) {
player.elements.poster.style.backgroundSize = 'cover';
}
}).catch(function () {});
var config = player.config.youtube; // Setup instance
loadImage(posterSrc('maxres'), 121) // Higest quality and unpadded
.catch(function () {
return loadImage(posterSrc('sd'), 121);
}) // 480p padded 4:3
.catch(function () {
return loadImage(posterSrc('hq'));
}) // 360p padded 4:3. Always exists
.then(function (image) {
return ui.setPoster.call(player, image.src);
}).then(function (src) {
// If the image is padded, use background-size "cover" instead (like youtube does too with their posters)
if (!src.includes('maxres')) {
player.elements.poster.style.backgroundSize = 'cover';
}
}).catch(function () {});
} // Setup instance
// https://developers.google.com/youtube/iframe_api_reference
player.embed = new window.YT.Player(id, {
player.embed = new window.YT.Player(player.media, {
videoId: videoId,
host: getHost$2(config),
playerVars: extend$1({}, {
autoplay: player.config.autoplay ? 1 : 0,
// Autoplay
hl: player.config.hl,
autoplay: player.config.autoplay ? 1 : 0,
// iframe interface language
controls: player.supported.ui ? 0 : 1,
// Only show controls if not fully supported
disablekb: 1,
hl: player.config.hl,
// Only show controls if not fully supported or opted out
controls: player.supported.ui && config.customControls ? 0 : 1,
// Disable keyboard as we handle it
playsinline: !player.config.fullscreen.iosNative ? 1 : 0,
disablekb: 1,
// Allow iOS inline playback
playsinline: !player.config.fullscreen.iosNative ? 1 : 0,
// Captions are flaky on YouTube
cc_load_policy: player.captions.active ? 1 : 0,
cc_lang_pref: player.config.captions.language,
@@ -26357,6 +26421,7 @@ typeof navigator === "object" && (function () {
var toggle = is$2.boolean(input) ? input : muted;
muted = toggle;
instance[toggle ? 'mute' : 'unMute']();
instance.setVolume(volume * 100);
triggerEvent.call(player, player.media, 'volumechange');
}
}); // Source
@@ -26379,7 +26444,7 @@ typeof navigator === "object" && (function () {
return player.config.speed.options.includes(s);
}); // Set the tabindex to avoid focus entering iframe
if (player.supported.ui) {
if (player.supported.ui && config.customControls) {
player.media.setAttribute('tabindex', -1);
}
@@ -26406,9 +26471,11 @@ typeof navigator === "object" && (function () {
}
}, 200); // Rebuild UI
setTimeout(function () {
return ui.build.call(player);
}, 50);
if (config.customControls) {
setTimeout(function () {
return ui.build.call(player);
}, 50);
}
},
onStateChange: function onStateChange(event) {
// Get the instance
@@ -26454,7 +26521,7 @@ typeof navigator === "object" && (function () {
case 1:
// Restore paused state (YouTube starts playing on seek if the video hasn't been played yet)
if (!player.config.autoplay && player.media.paused && !player.embed.hasPlayed) {
if (config.customControls && !player.config.autoplay && player.media.paused && !player.embed.hasPlayed) {
player.media.pause();
} else {
assurePlaybackState$1.call(player, true);
@@ -26527,7 +26594,8 @@ typeof navigator === "object" && (function () {
wrap$4(this.media, this.elements.wrapper); // Poster image container
this.elements.poster = createElement$1('div', {
class: this.config.classNames.poster
class: this.config.classNames.poster,
hidden: ''
});
this.elements.wrapper.appendChild(this.elements.poster);
}
@@ -28395,9 +28463,9 @@ typeof navigator === "object" && (function () {
if (this.isHTML5 && this.config.autoplay) {
setTimeout(function () {
this.once('canplay', function () {
return silencePromise(_this.play());
}, 10);
});
} // Seek time will be recorded (in listeners.js) so we can prevent hiding controls for a few seconds after seek
@@ -28686,7 +28754,9 @@ typeof navigator === "object" && (function () {
}
} else {
// Unbind listeners
unbindListeners.call(_this3); // Replace the container with the original element provided
unbindListeners.call(_this3); // Cancel current network requests
html5.cancelRequests.call(_this3); // Replace the container with the original element provided
replaceElement(_this3.elements.original, _this3.elements.container); // Event
+3 -3
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -5,10 +5,10 @@
"homepage": "https://plyr.io",
"author": "Sam Potts <sam@potts.es>",
"dependencies": {
"@sentry/browser": "^5.15.5",
"@sentry/browser": "^5.22.3",
"core-js": "^3.6.5",
"custom-event-polyfill": "^1.0.7",
"shr-buttons": "2.0.3",
"url-polyfill": "^1.1.8"
"url-polyfill": "^1.1.10"
}
}
+5 -5
View File
@@ -22,7 +22,7 @@ import toggleClass from './toggle-class';
if (window.location.host === production) {
Sentry.init({
dsn: 'https://d4ad9866ad834437a4754e23937071e4@sentry.io/305555',
whitelistUrls: [production].map(d => new RegExp(`https://(([a-z0-9])+(.))*${d}`)),
whitelistUrls: [production].map((d) => new RegExp(`https://(([a-z0-9])+(.))*${d}`)),
});
}
@@ -79,13 +79,13 @@ import toggleClass from './toggle-class';
function render(type) {
// Remove active classes
Array.from(buttons).forEach(button => toggleClass(button.parentElement, 'active', false));
Array.from(buttons).forEach((button) => toggleClass(button.parentElement, 'active', false));
// Set active on parent
toggleClass(document.querySelector(`[data-source="${type}"]`), 'active', true);
// Show cite
Array.from(document.querySelectorAll('.plyr__cite')).forEach(cite => {
Array.from(document.querySelectorAll('.plyr__cite')).forEach((cite) => {
// eslint-disable-next-line no-param-reassign
cite.hidden = true;
});
@@ -110,7 +110,7 @@ import toggleClass from './toggle-class';
}
// Bind to each button
Array.from(buttons).forEach(button => {
Array.from(buttons).forEach((button) => {
button.addEventListener('click', () => {
const type = button.getAttribute('data-source');
@@ -123,7 +123,7 @@ import toggleClass from './toggle-class';
});
// List for backwards/forwards
window.addEventListener('popstate', event => {
window.addEventListener('popstate', (event) => {
if (event.state && Object.keys(event.state).includes('type')) {
setSource(event.state.type);
}
+2 -2
View File
@@ -3,7 +3,7 @@ const container = document.getElementById('container');
const tabClassName = 'tab-focus';
// Remove class on blur
document.addEventListener('focusout', event => {
document.addEventListener('focusout', (event) => {
if (!event.target.classList || container.contains(event.target)) {
return;
}
@@ -12,7 +12,7 @@ document.addEventListener('focusout', event => {
});
// Add classname to tabbed elements
document.addEventListener('keydown', event => {
document.addEventListener('keydown', (event) => {
if (event.keyCode !== 9) {
return;
}
+1 -1
View File
@@ -4,7 +4,7 @@
// Example players
.plyr {
border-radius: $border-radius-base;
border-radius: $border-radius-large;
box-shadow: 0 2px 15px rgba(#000, 0.1);
margin: $spacing-base auto;
+1
View File
@@ -7,6 +7,7 @@ $arrow-size: 5px;
// Radii
$border-radius-base: 4px;
$border-radius-large: 8px;
// Background
$page-background: linear-gradient(to left top, $color-background-from, $color-background-to);
+40 -40
View File
@@ -2,56 +2,56 @@
# yarn lockfile v1
"@sentry/browser@^5.15.5":
version "5.15.5"
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-5.15.5.tgz#d9a51f1388581067b50d30ed9b1aed2cbb333a36"
integrity sha512-rqDvjk/EvogfdbZ4TiEpxM/lwpPKmq23z9YKEO4q81+1SwJNua53H60dOk9HpRU8nOJ1g84TMKT2Ov8H7sqDWA==
"@sentry/browser@^5.22.3":
version "5.22.3"
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-5.22.3.tgz#7a64bd1cf01bf393741a3e4bf35f82aa927f5b4e"
integrity sha512-2TzE/CoBa5ZkvxJizDdi1Iz1ldmXSJpFQ1mL07PIXBjCt0Wxf+WOuFSj5IP4L40XHfJE5gU8wEvSH0VDR8nXtA==
dependencies:
"@sentry/core" "5.15.5"
"@sentry/types" "5.15.5"
"@sentry/utils" "5.15.5"
"@sentry/core" "5.22.3"
"@sentry/types" "5.22.3"
"@sentry/utils" "5.22.3"
tslib "^1.9.3"
"@sentry/core@5.15.5":
version "5.15.5"
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-5.15.5.tgz#40ea79bff5272d3fbbeeb4a98cdc59e1adbd2c92"
integrity sha512-enxBLv5eibBMqcWyr+vApqeix8uqkfn0iGsD3piKvoMXCgKsrfMwlb/qo9Ox0lKr71qIlZVt+9/A2vZohdgnlg==
"@sentry/core@5.22.3":
version "5.22.3"
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-5.22.3.tgz#030f435f2b518f282ba8bd954dac90cd70888bd7"
integrity sha512-eGL5uUarw3o4i9QUb9JoFHnhriPpWCaqeaIBB06HUpdcvhrjoowcKZj1+WPec5lFg5XusE35vez7z/FPzmJUDw==
dependencies:
"@sentry/hub" "5.15.5"
"@sentry/minimal" "5.15.5"
"@sentry/types" "5.15.5"
"@sentry/utils" "5.15.5"
"@sentry/hub" "5.22.3"
"@sentry/minimal" "5.22.3"
"@sentry/types" "5.22.3"
"@sentry/utils" "5.22.3"
tslib "^1.9.3"
"@sentry/hub@5.15.5":
version "5.15.5"
resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-5.15.5.tgz#f5abbcdbe656a70e2ff02c02a5a4cffa0f125935"
integrity sha512-zX9o49PcNIVMA4BZHe//GkbQ4Jx+nVofqU/Il32/IbwKhcpPlhGX3c1sOVQo4uag3cqd/JuQsk+DML9TKkN0Lw==
"@sentry/hub@5.22.3":
version "5.22.3"
resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-5.22.3.tgz#08309a70d2ea8d5e313d05840c1711f34f2fffe5"
integrity sha512-INo47m6N5HFEs/7GMP9cqxOIt7rmRxdERunA3H2L37owjcr77MwHVeeJ9yawRS6FMtbWXplgWTyTIWIYOuqVbw==
dependencies:
"@sentry/types" "5.15.5"
"@sentry/utils" "5.15.5"
"@sentry/types" "5.22.3"
"@sentry/utils" "5.22.3"
tslib "^1.9.3"
"@sentry/minimal@5.15.5":
version "5.15.5"
resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-5.15.5.tgz#a0e4e071f01d9c4d808094ae7203f6c4cca9348a"
integrity sha512-zQkkJ1l9AjmU/Us5IrOTzu7bic4sTPKCatptXvLSTfyKW7N6K9MPIIFeSpZf9o1yM2sRYdK7GV08wS2eCT3JYw==
"@sentry/minimal@5.22.3":
version "5.22.3"
resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-5.22.3.tgz#706e4029ae5494123d3875c658ba8911aa5cc440"
integrity sha512-HoINpYnVYCpNjn2XIPIlqH5o4BAITpTljXjtAftOx6Hzj+Opjg8tR8PWliyKDvkXPpc4kXK9D6TpEDw8MO0wZA==
dependencies:
"@sentry/hub" "5.15.5"
"@sentry/types" "5.15.5"
"@sentry/hub" "5.22.3"
"@sentry/types" "5.22.3"
tslib "^1.9.3"
"@sentry/types@5.15.5":
version "5.15.5"
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-5.15.5.tgz#16c97e464cf09bbd1d2e8ce90d130e781709076e"
integrity sha512-F9A5W7ucgQLJUG4LXw1ZIy4iLevrYZzbeZ7GJ09aMlmXH9PqGThm1t5LSZlVpZvUfQ2rYA8NU6BdKJSt7B5LPw==
"@sentry/types@5.22.3":
version "5.22.3"
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-5.22.3.tgz#d1d547b30ee8bd7771fa893af74c4f3d71f0fd18"
integrity sha512-cv+VWK0YFgCVDvD1/HrrBWOWYG3MLuCUJRBTkV/Opdy7nkdNjhCAJQrEyMM9zX0sac8FKWKOHT0sykNh8KgmYw==
"@sentry/utils@5.15.5":
version "5.15.5"
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-5.15.5.tgz#dec1d4c79037c4da08b386f5d34409234dcbfb15"
integrity sha512-Nl9gl/MGnzSkuKeo3QaefoD/OJrFLB8HmwQ7HUbTXb6E7yyEzNKAQMHXGkwNAjbdYyYbd42iABP6Y5F/h39NtA==
"@sentry/utils@5.22.3":
version "5.22.3"
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-5.22.3.tgz#e3bda3e789239eb16d436f768daa12829f33d18f"
integrity sha512-AHNryXMBvIkIE+GQxTlmhBXD0Ksh+5w1SwM5qi6AttH+1qjWLvV6WB4+4pvVvEoS8t5F+WaVUZPQLmCCWp6zKw==
dependencies:
"@sentry/types" "5.15.5"
"@sentry/types" "5.22.3"
tslib "^1.9.3"
core-js@^3.6.5:
@@ -74,7 +74,7 @@ tslib@^1.9.3:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.1.tgz#eb15d128827fbee2841549e171f45ed338ac7e35"
integrity sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==
url-polyfill@^1.1.8:
version "1.1.8"
resolved "https://registry.yarnpkg.com/url-polyfill/-/url-polyfill-1.1.8.tgz#21eb58ad61192f52b77dcac8ab5293ae7bc67060"
integrity sha512-Ey61F4FEqhcu1vHSOMmjl0Vd/RPRLEjMj402qszD/dhMBrVfoUsnIj8KSZo2yj+eIlxJGKFdnm6ES+7UzMgZ3Q==
url-polyfill@^1.1.10:
version "1.1.10"
resolved "https://registry.yarnpkg.com/url-polyfill/-/url-polyfill-1.1.10.tgz#fd5bbcf66c9491fa682b0cb6d6a855e1643a9281"
integrity sha512-vSaPpaRgBrf41+Uky1myiSh6gpcbw8FpwHYnEy0abxndojOBnIs+yh/49gKYFLtUMP9qoNWjn6j9aUVy23Ie2A==
+1 -1
View File
File diff suppressed because one or more lines are too long
+111 -78
View File
@@ -1,7 +1,7 @@
typeof navigator === "object" && (function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define('Plyr', factory) :
(global = global || self, global.Plyr = factory());
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Plyr = factory());
}(this, (function () { 'use strict';
function _classCallCheck(instance, Constructor) {
@@ -1197,7 +1197,12 @@ typeof navigator === "object" && (function (global, factory) {
if (this.isVimeo && !this.config.vimeo.premium && this.supported.ui) {
var height = 100 / this.media.offsetWidth * parseInt(window.getComputedStyle(this.media).paddingBottom, 10);
var offset = (height - padding) / (height / 50);
this.media.style.transform = "translateY(-".concat(offset, "%)");
if (this.fullscreen.active) {
wrapper.style.paddingBottom = null;
} else {
this.media.style.transform = "translateY(-".concat(offset, "%)");
}
} else if (this.isHTML5) {
wrapper.classList.toggle(this.config.classNames.videoFixedRatio, ratio !== null);
}
@@ -3654,7 +3659,7 @@ typeof navigator === "object" && (function (global, factory) {
// Sprite (for icons)
loadSprite: true,
iconPrefix: 'plyr',
iconUrl: 'https://cdn.plyr.io/3.6.2/plyr.svg',
iconUrl: 'https://cdn.plyr.io/3.6.3/plyr.svg',
// Blank video (used to prevent errors on source change)
blankVideo: 'https://cdn.plyr.io/static/blank.mp4',
// Quality default
@@ -3772,7 +3777,7 @@ typeof navigator === "object" && (function (global, factory) {
vimeo: {
sdk: 'https://player.vimeo.com/api/player.js',
iframe: 'https://player.vimeo.com/video/{0}?{1}',
api: 'https://vimeo.com/api/v2/video/{0}.json'
api: 'https://vimeo.com/api/oembed.json?url={0}'
},
youtube: {
sdk: 'https://www.youtube.com/iframe_api',
@@ -3942,24 +3947,27 @@ typeof navigator === "object" && (function (global, factory) {
title: false,
speed: true,
transparent: false,
// Custom settings from Plyr
customControls: true,
referrerPolicy: null,
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/referrerPolicy
// Whether the owner of the video has a Pro or Business account
// (which allows us to properly hide controls without CSS hacks, etc)
premium: false,
// Custom settings from Plyr
referrerPolicy: null // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/referrerPolicy
premium: false
},
// YouTube plugin
youtube: {
noCookie: true,
// Whether to use an alternative version of YouTube without cookies
rel: 0,
// No related vids
showinfo: 0,
// Hide info
iv_load_policy: 3,
// Hide annotations
modestbranding: 1 // Hide logos as much as possible (they still show one in the corner when paused)
modestbranding: 1,
// Hide logos as much as possible (they still show one in the corner when paused)
// Custom settings from Plyr
customControls: true,
noCookie: false // Whether to use an alternative version of YouTube without cookies
}
};
@@ -4078,7 +4086,7 @@ typeof navigator === "object" && (function (global, factory) {
return;
}
_this.toggle();
_this.player.listeners.proxy(event, _this.toggle, 'fullscreen');
}); // Tap focus when in fullscreen
on.call(this, this.player.elements.container, 'keydown', function (event) {
@@ -4101,10 +4109,12 @@ typeof navigator === "object" && (function (global, factory) {
if (is$1.element(button)) {
button.pressed = this.active;
} // Trigger an event
} // Always trigger events on the plyr / media element (not a fullscreen container) and let them bubble up
triggerEvent.call(this.player, this.target, this.active ? 'enterfullscreen' : 'exitfullscreen', true);
var target = this.target === this.player.media ? this.target : this.player.elements.container; // Trigger an event
triggerEvent.call(this.player, target, this.active ? 'enterfullscreen' : 'exitfullscreen', true);
}
}, {
key: "toggleFallback",
@@ -4486,7 +4496,9 @@ typeof navigator === "object" && (function (global, factory) {
} // Set property synchronously to respect the call order
this.media.setAttribute('data-poster', poster); // Wait until ui is ready
this.media.setAttribute('data-poster', poster); // Show the poster
this.elements.poster.removeAttribute('hidden'); // Wait until ui is ready
return ready.call(this) // Load image
.then(function () {
@@ -4570,7 +4582,7 @@ typeof navigator === "object" && (function (global, factory) {
// Loop through values (as they are the keys when the object is spread 🤔)
Object.values(_objectSpread2({}, this.media.style)) // We're only fussed about Plyr specific properties
.filter(function (key) {
return !is$1.empty(key) && key.startsWith('--plyr');
return !is$1.empty(key) && is$1.string(key) && key.startsWith('--plyr');
}).forEach(function (key) {
// Set on the container
_this5.elements.container.style.setProperty(key, _this5.media.style.getPropertyValue(key)); // Clean up from media element
@@ -4918,7 +4930,14 @@ typeof navigator === "object" && (function (global, factory) {
ratio = _setPlayerSize.ratio; // Set Vimeo gutter
setGutter(ratio, padding, isEnter); // If not using native browser fullscreen API, we need to check for resizes of viewport
setGutter(ratio, padding, isEnter); // Horrible hack for Safari 14 not repainting properly on entering fullscreen
if (isEnter) {
setTimeout(function () {
return repaint(elements.container);
}, 100);
} // If not using native browser fullscreen API, we need to check for resizes of viewport
if (!usingNative) {
if (isEnter) {
@@ -5109,9 +5128,17 @@ typeof navigator === "object" && (function (global, factory) {
this.bind(elements.buttons.restart, 'click', player.restart, 'restart'); // Rewind
this.bind(elements.buttons.rewind, 'click', player.rewind, 'rewind'); // Rewind
this.bind(elements.buttons.rewind, 'click', function () {
// Record seek time so we can prevent hiding controls for a few seconds after rewind
player.lastSeekTime = Date.now();
player.rewind();
}, 'rewind'); // Rewind
this.bind(elements.buttons.fastForward, 'click', player.forward, 'fastForward'); // Mute toggle
this.bind(elements.buttons.fastForward, 'click', function () {
// Record seek time so we can prevent hiding controls for a few seconds after fast forward
player.lastSeekTime = Date.now();
player.forward();
}, 'fastForward'); // Mute toggle
this.bind(elements.buttons.mute, 'click', function () {
player.muted = !player.muted;
@@ -5766,35 +5793,32 @@ typeof navigator === "object" && (function (global, factory) {
} // Inject the package
var poster = player.poster;
if (premium) {
iframe.setAttribute('data-poster', poster);
if (premium || !config.customControls) {
iframe.setAttribute('data-poster', player.poster);
player.media = replaceElement(iframe, player.media);
} else {
var wrapper = createElement('div', {
class: player.config.classNames.embedContainer,
'data-poster': poster
'data-poster': player.poster
});
wrapper.appendChild(iframe);
player.media = replaceElement(wrapper, player.media);
} // Get poster image
fetch(format(player.config.urls.vimeo.api, id), 'json').then(function (response) {
if (is$1.empty(response)) {
return;
} // Get the URL for thumbnail
if (!config.customControls) {
fetch(format(player.config.urls.vimeo.api, src)).then(function (response) {
if (is$1.empty(response) || !response.thumbnail_url) {
return;
} // Set and show poster
var url = new URL(response[0].thumbnail_large); // Get original image
url.pathname = "".concat(url.pathname.split('_')[0], ".jpg"); // Set and show poster
ui.setPoster.call(player, url.href).catch(function () {});
}); // Setup instance
ui.setPoster.call(player, response.thumbnail_url).catch(function () {});
});
} // Setup instance
// https://github.com/vimeo/player.js
player.embed = new window.Vimeo.Player(iframe, {
autopause: player.config.autopause,
muted: player.muted
@@ -6034,9 +6058,11 @@ typeof navigator === "object" && (function (global, factory) {
triggerEvent.call(player, player.media, 'error');
}); // Rebuild UI
setTimeout(function () {
return ui.build.call(player);
}, 0);
if (config.customControls) {
setTimeout(function () {
return ui.build.call(player);
}, 0);
}
}
};
@@ -6129,7 +6155,8 @@ typeof navigator === "object" && (function (global, factory) {
},
// API ready
ready: function ready() {
var player = this; // Ignore already setup (race condition)
var player = this;
var config = player.config.youtube; // Ignore already setup (race condition)
var currentId = player.media && player.media.getAttribute('id');
@@ -6146,53 +6173,53 @@ typeof navigator === "object" && (function (global, factory) {
var videoId = parseId$1(source);
var id = generateId(player.provider); // Get poster, if already set
var poster = player.poster; // Replace media element
var id = generateId(player.provider); // Replace media element
var container = createElement('div', {
id: id,
'data-poster': poster
'data-poster': config.customControls ? player.poster : undefined
});
player.media = replaceElement(container, player.media); // Id to poster wrapper
player.media = replaceElement(container, player.media); // Only load the poster when using custom controls
var posterSrc = function posterSrc(s) {
return "https://i.ytimg.com/vi/".concat(videoId, "/").concat(s, "default.jpg");
}; // Check thumbnail images in order of quality, but reject fallback thumbnails (120px wide)
if (config.customControls) {
var posterSrc = function posterSrc(s) {
return "https://i.ytimg.com/vi/".concat(videoId, "/").concat(s, "default.jpg");
}; // Check thumbnail images in order of quality, but reject fallback thumbnails (120px wide)
loadImage(posterSrc('maxres'), 121) // Higest quality and unpadded
.catch(function () {
return loadImage(posterSrc('sd'), 121);
}) // 480p padded 4:3
.catch(function () {
return loadImage(posterSrc('hq'));
}) // 360p padded 4:3. Always exists
.then(function (image) {
return ui.setPoster.call(player, image.src);
}).then(function (src) {
// If the image is padded, use background-size "cover" instead (like youtube does too with their posters)
if (!src.includes('maxres')) {
player.elements.poster.style.backgroundSize = 'cover';
}
}).catch(function () {});
var config = player.config.youtube; // Setup instance
loadImage(posterSrc('maxres'), 121) // Higest quality and unpadded
.catch(function () {
return loadImage(posterSrc('sd'), 121);
}) // 480p padded 4:3
.catch(function () {
return loadImage(posterSrc('hq'));
}) // 360p padded 4:3. Always exists
.then(function (image) {
return ui.setPoster.call(player, image.src);
}).then(function (src) {
// If the image is padded, use background-size "cover" instead (like youtube does too with their posters)
if (!src.includes('maxres')) {
player.elements.poster.style.backgroundSize = 'cover';
}
}).catch(function () {});
} // Setup instance
// https://developers.google.com/youtube/iframe_api_reference
player.embed = new window.YT.Player(id, {
player.embed = new window.YT.Player(player.media, {
videoId: videoId,
host: getHost(config),
playerVars: extend({}, {
autoplay: player.config.autoplay ? 1 : 0,
// Autoplay
hl: player.config.hl,
autoplay: player.config.autoplay ? 1 : 0,
// iframe interface language
controls: player.supported.ui ? 0 : 1,
// Only show controls if not fully supported
disablekb: 1,
hl: player.config.hl,
// Only show controls if not fully supported or opted out
controls: player.supported.ui && config.customControls ? 0 : 1,
// Disable keyboard as we handle it
playsinline: !player.config.fullscreen.iosNative ? 1 : 0,
disablekb: 1,
// Allow iOS inline playback
playsinline: !player.config.fullscreen.iosNative ? 1 : 0,
// Captions are flaky on YouTube
cc_load_policy: player.captions.active ? 1 : 0,
cc_lang_pref: player.config.captions.language,
@@ -6303,6 +6330,7 @@ typeof navigator === "object" && (function (global, factory) {
var toggle = is$1.boolean(input) ? input : muted;
muted = toggle;
instance[toggle ? 'mute' : 'unMute']();
instance.setVolume(volume * 100);
triggerEvent.call(player, player.media, 'volumechange');
}
}); // Source
@@ -6325,7 +6353,7 @@ typeof navigator === "object" && (function (global, factory) {
return player.config.speed.options.includes(s);
}); // Set the tabindex to avoid focus entering iframe
if (player.supported.ui) {
if (player.supported.ui && config.customControls) {
player.media.setAttribute('tabindex', -1);
}
@@ -6352,9 +6380,11 @@ typeof navigator === "object" && (function (global, factory) {
}
}, 200); // Rebuild UI
setTimeout(function () {
return ui.build.call(player);
}, 50);
if (config.customControls) {
setTimeout(function () {
return ui.build.call(player);
}, 50);
}
},
onStateChange: function onStateChange(event) {
// Get the instance
@@ -6400,7 +6430,7 @@ typeof navigator === "object" && (function (global, factory) {
case 1:
// Restore paused state (YouTube starts playing on seek if the video hasn't been played yet)
if (!player.config.autoplay && player.media.paused && !player.embed.hasPlayed) {
if (config.customControls && !player.config.autoplay && player.media.paused && !player.embed.hasPlayed) {
player.media.pause();
} else {
assurePlaybackState$1.call(player, true);
@@ -6474,7 +6504,8 @@ typeof navigator === "object" && (function (global, factory) {
wrap(this.media, this.elements.wrapper); // Poster image container
this.elements.poster = createElement('div', {
class: this.config.classNames.poster
class: this.config.classNames.poster,
hidden: ''
});
this.elements.wrapper.appendChild(this.elements.poster);
}
@@ -8291,9 +8322,9 @@ typeof navigator === "object" && (function (global, factory) {
if (this.isHTML5 && this.config.autoplay) {
setTimeout(function () {
this.once('canplay', function () {
return silencePromise(_this.play());
}, 10);
});
} // Seek time will be recorded (in listeners.js) so we can prevent hiding controls for a few seconds after seek
@@ -8582,7 +8613,9 @@ typeof navigator === "object" && (function (global, factory) {
}
} else {
// Unbind listeners
unbindListeners.call(_this3); // Replace the container with the original element provided
unbindListeners.call(_this3); // Cancel current network requests
html5.cancelRequests.call(_this3); // Replace the container with the original element provided
replaceElement(_this3.elements.original, _this3.elements.container); // Event
+2 -2
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+2 -2
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+111 -78
View File
@@ -1,4 +1,4 @@
typeof navigator === "object" && function _classCallCheck(instance, Constructor) {
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
@@ -1191,7 +1191,12 @@ function setAspectRatio(input) {
if (this.isVimeo && !this.config.vimeo.premium && this.supported.ui) {
var height = 100 / this.media.offsetWidth * parseInt(window.getComputedStyle(this.media).paddingBottom, 10);
var offset = (height - padding) / (height / 50);
this.media.style.transform = "translateY(-".concat(offset, "%)");
if (this.fullscreen.active) {
wrapper.style.paddingBottom = null;
} else {
this.media.style.transform = "translateY(-".concat(offset, "%)");
}
} else if (this.isHTML5) {
wrapper.classList.toggle(this.config.classNames.videoFixedRatio, ratio !== null);
}
@@ -3648,7 +3653,7 @@ var defaults$1 = {
// Sprite (for icons)
loadSprite: true,
iconPrefix: 'plyr',
iconUrl: 'https://cdn.plyr.io/3.6.2/plyr.svg',
iconUrl: 'https://cdn.plyr.io/3.6.3/plyr.svg',
// Blank video (used to prevent errors on source change)
blankVideo: 'https://cdn.plyr.io/static/blank.mp4',
// Quality default
@@ -3766,7 +3771,7 @@ var defaults$1 = {
vimeo: {
sdk: 'https://player.vimeo.com/api/player.js',
iframe: 'https://player.vimeo.com/video/{0}?{1}',
api: 'https://vimeo.com/api/v2/video/{0}.json'
api: 'https://vimeo.com/api/oembed.json?url={0}'
},
youtube: {
sdk: 'https://www.youtube.com/iframe_api',
@@ -3936,24 +3941,27 @@ var defaults$1 = {
title: false,
speed: true,
transparent: false,
// Custom settings from Plyr
customControls: true,
referrerPolicy: null,
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/referrerPolicy
// Whether the owner of the video has a Pro or Business account
// (which allows us to properly hide controls without CSS hacks, etc)
premium: false,
// Custom settings from Plyr
referrerPolicy: null // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/referrerPolicy
premium: false
},
// YouTube plugin
youtube: {
noCookie: true,
// Whether to use an alternative version of YouTube without cookies
rel: 0,
// No related vids
showinfo: 0,
// Hide info
iv_load_policy: 3,
// Hide annotations
modestbranding: 1 // Hide logos as much as possible (they still show one in the corner when paused)
modestbranding: 1,
// Hide logos as much as possible (they still show one in the corner when paused)
// Custom settings from Plyr
customControls: true,
noCookie: false // Whether to use an alternative version of YouTube without cookies
}
};
@@ -4072,7 +4080,7 @@ var Fullscreen = /*#__PURE__*/function () {
return;
}
_this.toggle();
_this.player.listeners.proxy(event, _this.toggle, 'fullscreen');
}); // Tap focus when in fullscreen
on.call(this, this.player.elements.container, 'keydown', function (event) {
@@ -4095,10 +4103,12 @@ var Fullscreen = /*#__PURE__*/function () {
if (is$1.element(button)) {
button.pressed = this.active;
} // Trigger an event
} // Always trigger events on the plyr / media element (not a fullscreen container) and let them bubble up
triggerEvent.call(this.player, this.target, this.active ? 'enterfullscreen' : 'exitfullscreen', true);
var target = this.target === this.player.media ? this.target : this.player.elements.container; // Trigger an event
triggerEvent.call(this.player, target, this.active ? 'enterfullscreen' : 'exitfullscreen', true);
}
}, {
key: "toggleFallback",
@@ -4480,7 +4490,9 @@ var ui = {
} // Set property synchronously to respect the call order
this.media.setAttribute('data-poster', poster); // Wait until ui is ready
this.media.setAttribute('data-poster', poster); // Show the poster
this.elements.poster.removeAttribute('hidden'); // Wait until ui is ready
return ready.call(this) // Load image
.then(function () {
@@ -4564,7 +4576,7 @@ var ui = {
// Loop through values (as they are the keys when the object is spread 🤔)
Object.values(_objectSpread2({}, this.media.style)) // We're only fussed about Plyr specific properties
.filter(function (key) {
return !is$1.empty(key) && key.startsWith('--plyr');
return !is$1.empty(key) && is$1.string(key) && key.startsWith('--plyr');
}).forEach(function (key) {
// Set on the container
_this5.elements.container.style.setProperty(key, _this5.media.style.getPropertyValue(key)); // Clean up from media element
@@ -4912,7 +4924,14 @@ var Listeners = /*#__PURE__*/function () {
ratio = _setPlayerSize.ratio; // Set Vimeo gutter
setGutter(ratio, padding, isEnter); // If not using native browser fullscreen API, we need to check for resizes of viewport
setGutter(ratio, padding, isEnter); // Horrible hack for Safari 14 not repainting properly on entering fullscreen
if (isEnter) {
setTimeout(function () {
return repaint(elements.container);
}, 100);
} // If not using native browser fullscreen API, we need to check for resizes of viewport
if (!usingNative) {
if (isEnter) {
@@ -5103,9 +5122,17 @@ var Listeners = /*#__PURE__*/function () {
this.bind(elements.buttons.restart, 'click', player.restart, 'restart'); // Rewind
this.bind(elements.buttons.rewind, 'click', player.rewind, 'rewind'); // Rewind
this.bind(elements.buttons.rewind, 'click', function () {
// Record seek time so we can prevent hiding controls for a few seconds after rewind
player.lastSeekTime = Date.now();
player.rewind();
}, 'rewind'); // Rewind
this.bind(elements.buttons.fastForward, 'click', player.forward, 'fastForward'); // Mute toggle
this.bind(elements.buttons.fastForward, 'click', function () {
// Record seek time so we can prevent hiding controls for a few seconds after fast forward
player.lastSeekTime = Date.now();
player.forward();
}, 'fastForward'); // Mute toggle
this.bind(elements.buttons.mute, 'click', function () {
player.muted = !player.muted;
@@ -5760,35 +5787,32 @@ var vimeo = {
} // Inject the package
var poster = player.poster;
if (premium) {
iframe.setAttribute('data-poster', poster);
if (premium || !config.customControls) {
iframe.setAttribute('data-poster', player.poster);
player.media = replaceElement(iframe, player.media);
} else {
var wrapper = createElement('div', {
class: player.config.classNames.embedContainer,
'data-poster': poster
'data-poster': player.poster
});
wrapper.appendChild(iframe);
player.media = replaceElement(wrapper, player.media);
} // Get poster image
fetch(format(player.config.urls.vimeo.api, id), 'json').then(function (response) {
if (is$1.empty(response)) {
return;
} // Get the URL for thumbnail
if (!config.customControls) {
fetch(format(player.config.urls.vimeo.api, src)).then(function (response) {
if (is$1.empty(response) || !response.thumbnail_url) {
return;
} // Set and show poster
var url = new URL(response[0].thumbnail_large); // Get original image
url.pathname = "".concat(url.pathname.split('_')[0], ".jpg"); // Set and show poster
ui.setPoster.call(player, url.href).catch(function () {});
}); // Setup instance
ui.setPoster.call(player, response.thumbnail_url).catch(function () {});
});
} // Setup instance
// https://github.com/vimeo/player.js
player.embed = new window.Vimeo.Player(iframe, {
autopause: player.config.autopause,
muted: player.muted
@@ -6028,9 +6052,11 @@ var vimeo = {
triggerEvent.call(player, player.media, 'error');
}); // Rebuild UI
setTimeout(function () {
return ui.build.call(player);
}, 0);
if (config.customControls) {
setTimeout(function () {
return ui.build.call(player);
}, 0);
}
}
};
@@ -6123,7 +6149,8 @@ var youtube = {
},
// API ready
ready: function ready() {
var player = this; // Ignore already setup (race condition)
var player = this;
var config = player.config.youtube; // Ignore already setup (race condition)
var currentId = player.media && player.media.getAttribute('id');
@@ -6140,53 +6167,53 @@ var youtube = {
var videoId = parseId$1(source);
var id = generateId(player.provider); // Get poster, if already set
var poster = player.poster; // Replace media element
var id = generateId(player.provider); // Replace media element
var container = createElement('div', {
id: id,
'data-poster': poster
'data-poster': config.customControls ? player.poster : undefined
});
player.media = replaceElement(container, player.media); // Id to poster wrapper
player.media = replaceElement(container, player.media); // Only load the poster when using custom controls
var posterSrc = function posterSrc(s) {
return "https://i.ytimg.com/vi/".concat(videoId, "/").concat(s, "default.jpg");
}; // Check thumbnail images in order of quality, but reject fallback thumbnails (120px wide)
if (config.customControls) {
var posterSrc = function posterSrc(s) {
return "https://i.ytimg.com/vi/".concat(videoId, "/").concat(s, "default.jpg");
}; // Check thumbnail images in order of quality, but reject fallback thumbnails (120px wide)
loadImage(posterSrc('maxres'), 121) // Higest quality and unpadded
.catch(function () {
return loadImage(posterSrc('sd'), 121);
}) // 480p padded 4:3
.catch(function () {
return loadImage(posterSrc('hq'));
}) // 360p padded 4:3. Always exists
.then(function (image) {
return ui.setPoster.call(player, image.src);
}).then(function (src) {
// If the image is padded, use background-size "cover" instead (like youtube does too with their posters)
if (!src.includes('maxres')) {
player.elements.poster.style.backgroundSize = 'cover';
}
}).catch(function () {});
var config = player.config.youtube; // Setup instance
loadImage(posterSrc('maxres'), 121) // Higest quality and unpadded
.catch(function () {
return loadImage(posterSrc('sd'), 121);
}) // 480p padded 4:3
.catch(function () {
return loadImage(posterSrc('hq'));
}) // 360p padded 4:3. Always exists
.then(function (image) {
return ui.setPoster.call(player, image.src);
}).then(function (src) {
// If the image is padded, use background-size "cover" instead (like youtube does too with their posters)
if (!src.includes('maxres')) {
player.elements.poster.style.backgroundSize = 'cover';
}
}).catch(function () {});
} // Setup instance
// https://developers.google.com/youtube/iframe_api_reference
player.embed = new window.YT.Player(id, {
player.embed = new window.YT.Player(player.media, {
videoId: videoId,
host: getHost(config),
playerVars: extend({}, {
autoplay: player.config.autoplay ? 1 : 0,
// Autoplay
hl: player.config.hl,
autoplay: player.config.autoplay ? 1 : 0,
// iframe interface language
controls: player.supported.ui ? 0 : 1,
// Only show controls if not fully supported
disablekb: 1,
hl: player.config.hl,
// Only show controls if not fully supported or opted out
controls: player.supported.ui && config.customControls ? 0 : 1,
// Disable keyboard as we handle it
playsinline: !player.config.fullscreen.iosNative ? 1 : 0,
disablekb: 1,
// Allow iOS inline playback
playsinline: !player.config.fullscreen.iosNative ? 1 : 0,
// Captions are flaky on YouTube
cc_load_policy: player.captions.active ? 1 : 0,
cc_lang_pref: player.config.captions.language,
@@ -6297,6 +6324,7 @@ var youtube = {
var toggle = is$1.boolean(input) ? input : muted;
muted = toggle;
instance[toggle ? 'mute' : 'unMute']();
instance.setVolume(volume * 100);
triggerEvent.call(player, player.media, 'volumechange');
}
}); // Source
@@ -6319,7 +6347,7 @@ var youtube = {
return player.config.speed.options.includes(s);
}); // Set the tabindex to avoid focus entering iframe
if (player.supported.ui) {
if (player.supported.ui && config.customControls) {
player.media.setAttribute('tabindex', -1);
}
@@ -6346,9 +6374,11 @@ var youtube = {
}
}, 200); // Rebuild UI
setTimeout(function () {
return ui.build.call(player);
}, 50);
if (config.customControls) {
setTimeout(function () {
return ui.build.call(player);
}, 50);
}
},
onStateChange: function onStateChange(event) {
// Get the instance
@@ -6394,7 +6424,7 @@ var youtube = {
case 1:
// Restore paused state (YouTube starts playing on seek if the video hasn't been played yet)
if (!player.config.autoplay && player.media.paused && !player.embed.hasPlayed) {
if (config.customControls && !player.config.autoplay && player.media.paused && !player.embed.hasPlayed) {
player.media.pause();
} else {
assurePlaybackState$1.call(player, true);
@@ -6468,7 +6498,8 @@ var media = {
wrap(this.media, this.elements.wrapper); // Poster image container
this.elements.poster = createElement('div', {
class: this.config.classNames.poster
class: this.config.classNames.poster,
hidden: ''
});
this.elements.wrapper.appendChild(this.elements.poster);
}
@@ -8285,9 +8316,9 @@ var Plyr = /*#__PURE__*/function () {
if (this.isHTML5 && this.config.autoplay) {
setTimeout(function () {
this.once('canplay', function () {
return silencePromise(_this.play());
}, 10);
});
} // Seek time will be recorded (in listeners.js) so we can prevent hiding controls for a few seconds after seek
@@ -8576,7 +8607,9 @@ var Plyr = /*#__PURE__*/function () {
}
} else {
// Unbind listeners
unbindListeners.call(_this3); // Replace the container with the original element provided
unbindListeners.call(_this3); // Cancel current network requests
html5.cancelRequests.call(_this3); // Replace the container with the original element provided
replaceElement(_this3.elements.original, _this3.elements.container); // Event
+228 -152
View File
@@ -1,7 +1,7 @@
typeof navigator === "object" && (function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define('Plyr', factory) :
(global = global || self, global.Plyr = factory());
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Plyr = factory());
}(this, (function () { 'use strict';
// Polyfill for creating CustomEvents on IE9/10/11
@@ -74,7 +74,7 @@ typeof navigator === "object" && (function (global, factory) {
check(typeof self == 'object' && self) ||
check(typeof commonjsGlobal == 'object' && commonjsGlobal) ||
// eslint-disable-next-line no-new-func
Function('return this')();
(function () { return this; })() || Function('return this')();
var fails = function (exec) {
try {
@@ -269,7 +269,7 @@ typeof navigator === "object" && (function (global, factory) {
(module.exports = function (key, value) {
return sharedStore[key] || (sharedStore[key] = value !== undefined ? value : {});
})('versions', []).push({
version: '3.6.5',
version: '3.7.0',
mode: 'global',
copyright: '© 2020 Denis Pushkarev (zloirock.ru)'
});
@@ -307,11 +307,12 @@ typeof navigator === "object" && (function (global, factory) {
};
if (nativeWeakMap) {
var store$1 = new WeakMap$2();
var store$1 = sharedStore.state || (sharedStore.state = new WeakMap$2());
var wmget = store$1.get;
var wmhas = store$1.has;
var wmset = store$1.set;
set = function (it, metadata) {
metadata.facade = it;
wmset.call(store$1, it, metadata);
return metadata;
};
@@ -325,6 +326,7 @@ typeof navigator === "object" && (function (global, factory) {
var STATE = sharedKey('state');
hiddenKeys[STATE] = true;
set = function (it, metadata) {
metadata.facade = it;
createNonEnumerableProperty(it, STATE, metadata);
return metadata;
};
@@ -353,9 +355,15 @@ typeof navigator === "object" && (function (global, factory) {
var unsafe = options ? !!options.unsafe : false;
var simple = options ? !!options.enumerable : false;
var noTargetGet = options ? !!options.noTargetGet : false;
var state;
if (typeof value == 'function') {
if (typeof key == 'string' && !has(value, 'name')) createNonEnumerableProperty(value, 'name', key);
enforceInternalState(value).source = TEMPLATE.join(typeof key == 'string' ? key : '');
if (typeof key == 'string' && !has(value, 'name')) {
createNonEnumerableProperty(value, 'name', key);
}
state = enforceInternalState(value);
if (!state.source) {
state.source = TEMPLATE.join(typeof key == 'string' ? key : '');
}
}
if (O === global_1) {
if (simple) O[key] = value;
@@ -2441,14 +2449,20 @@ typeof navigator === "object" && (function (global, factory) {
} return T;
} : nativeAssign;
var iteratorClose = function (iterator) {
var returnMethod = iterator['return'];
if (returnMethod !== undefined) {
return anObject(returnMethod.call(iterator)).value;
}
};
// call something on iterator step with safe closing on error
var callWithSafeIterationClosing = function (iterator, fn, value, ENTRIES) {
try {
return ENTRIES ? fn(anObject(value)[0], value[1]) : fn(value);
// 7.4.6 IteratorClose(iterator, completion)
} catch (error) {
var returnMethod = iterator['return'];
if (returnMethod !== undefined) anObject(returnMethod.call(iterator));
iteratorClose(iterator);
throw error;
}
};
@@ -2845,7 +2859,7 @@ typeof navigator === "object" && (function (global, factory) {
var URLSearchParamsPrototype = URLSearchParamsConstructor.prototype;
redefineAll(URLSearchParamsPrototype, {
// `URLSearchParams.prototype.appent` method
// `URLSearchParams.prototype.append` method
// https://url.spec.whatwg.org/#dom-urlsearchparams-append
append: function append(name, value) {
validateArgumentsLength(arguments.length, 2);
@@ -4408,7 +4422,7 @@ typeof navigator === "object" && (function (global, factory) {
var checkIfURLSearchParamsSupported = function checkIfURLSearchParamsSupported() {
try {
var URLSearchParams = global.URLSearchParams;
return new URLSearchParams('?a=1').toString() === 'a=1' && typeof URLSearchParams.prototype.set === 'function';
return new URLSearchParams('?a=1').toString() === 'a=1' && typeof URLSearchParams.prototype.set === 'function' && typeof URLSearchParams.prototype.entries === 'function';
} catch (e) {
return false;
}
@@ -4506,12 +4520,14 @@ typeof navigator === "object" && (function (global, factory) {
var _URL = global.URL;
var URL = function URL(url, base) {
if (typeof url !== 'string') url = String(url); // Only create another document if the base is different from current location.
if (typeof url !== 'string') url = String(url);
if (base && typeof base !== 'string') base = String(base); // Only create another document if the base is different from current location.
var doc = document,
baseElement;
if (base && (global.location === void 0 || base !== global.location.href)) {
base = base.toLowerCase();
doc = document.implementation.createHTMLDocument('');
baseElement = doc.createElement('base');
baseElement.href = base;
@@ -4532,7 +4548,11 @@ typeof navigator === "object" && (function (global, factory) {
anchorElement.href = anchorElement.href; // force href to refresh
}
if (anchorElement.protocol === ':' || !/:/.test(anchorElement.href)) {
var inputElement = doc.createElement('input');
inputElement.type = 'url';
inputElement.value = url;
if (anchorElement.protocol === ':' || !/:/.test(anchorElement.href) || !inputElement.checkValidity() && !base) {
throw new TypeError('Invalid URL');
}
@@ -5013,11 +5033,11 @@ typeof navigator === "object" && (function (global, factory) {
var regexp = /./;
try {
'/./'[METHOD_NAME](regexp);
} catch (e) {
} catch (error1) {
try {
regexp[MATCH$1] = false;
return '/./'[METHOD_NAME](regexp);
} catch (f) { /* empty */ }
} catch (error2) { /* empty */ }
} return false;
};
@@ -5099,16 +5119,31 @@ typeof navigator === "object" && (function (global, factory) {
var internalMetadata_3 = internalMetadata.getWeakData;
var internalMetadata_4 = internalMetadata.onFreeze;
var iterate_1 = createCommonjsModule(function (module) {
var Result = function (stopped, result) {
this.stopped = stopped;
this.result = result;
};
var iterate = module.exports = function (iterable, fn, that, AS_ENTRIES, IS_ITERATOR) {
var boundFunction = functionBindContext(fn, that, AS_ENTRIES ? 2 : 1);
var iterate = function (iterable, unboundFunction, options) {
var that = options && options.that;
var AS_ENTRIES = !!(options && options.AS_ENTRIES);
var IS_ITERATOR = !!(options && options.IS_ITERATOR);
var INTERRUPTED = !!(options && options.INTERRUPTED);
var fn = functionBindContext(unboundFunction, that, 1 + AS_ENTRIES + INTERRUPTED);
var iterator, iterFn, index, length, result, next, step;
var stop = function (condition) {
if (iterator) iteratorClose(iterator);
return new Result(true, condition);
};
var callFn = function (value) {
if (AS_ENTRIES) {
anObject(value);
return INTERRUPTED ? fn(value[0], value[1], stop) : fn(value[0], value[1]);
} return INTERRUPTED ? fn(value, stop) : fn(value);
};
if (IS_ITERATOR) {
iterator = iterable;
} else {
@@ -5117,9 +5152,7 @@ typeof navigator === "object" && (function (global, factory) {
// optimisation for array iterators
if (isArrayIteratorMethod(iterFn)) {
for (index = 0, length = toLength(iterable.length); length > index; index++) {
result = AS_ENTRIES
? boundFunction(anObject(step = iterable[index])[0], step[1])
: boundFunction(iterable[index]);
result = callFn(iterable[index]);
if (result && result instanceof Result) return result;
} return new Result(false);
}
@@ -5128,16 +5161,16 @@ typeof navigator === "object" && (function (global, factory) {
next = iterator.next;
while (!(step = next.call(iterator)).done) {
result = callWithSafeIterationClosing(iterator, boundFunction, step.value, AS_ENTRIES);
try {
result = callFn(step.value);
} catch (error) {
iteratorClose(iterator);
throw error;
}
if (typeof result == 'object' && result && result instanceof Result) return result;
} return new Result(false);
};
iterate.stop = function (result) {
return new Result(true, result);
};
});
var collection = function (CONSTRUCTOR_NAME, wrapper, common) {
var IS_MAP = CONSTRUCTOR_NAME.indexOf('Map') !== -1;
var IS_WEAK = CONSTRUCTOR_NAME.indexOf('Weak') !== -1;
@@ -5195,7 +5228,7 @@ typeof navigator === "object" && (function (global, factory) {
Constructor = wrapper(function (dummy, iterable) {
anInstance(dummy, Constructor, CONSTRUCTOR_NAME);
var that = inheritIfRequired(new NativeConstructor(), dummy, Constructor);
if (iterable != undefined) iterate_1(iterable, that[ADDER], that, IS_MAP);
if (iterable != undefined) iterate(iterable, that[ADDER], { that: that, AS_ENTRIES: IS_MAP });
return that;
});
Constructor.prototype = NativePrototype;
@@ -5285,7 +5318,7 @@ typeof navigator === "object" && (function (global, factory) {
id: id$1++,
frozen: undefined
});
if (iterable != undefined) iterate_1(iterable, that[ADDER], that, IS_MAP);
if (iterable != undefined) iterate(iterable, that[ADDER], { that: that, AS_ENTRIES: IS_MAP });
});
var getInternalState = internalStateGetterFor(CONSTRUCTOR_NAME);
@@ -5974,6 +6007,8 @@ typeof navigator === "object" && (function (global, factory) {
var engineIsIos = /(iphone|ipod|ipad).*applewebkit/i.test(engineUserAgent);
var engineIsNode = classofRaw(global_1.process) == 'process';
var location = global_1.location;
var set$1 = global_1.setImmediate;
var clear = global_1.clearImmediate;
@@ -6026,7 +6061,7 @@ typeof navigator === "object" && (function (global, factory) {
delete queue[id];
};
// Node.js 0.8-
if (classofRaw(process$1) == 'process') {
if (engineIsNode) {
defer = function (id) {
process$1.nextTick(runner(id));
};
@@ -6048,8 +6083,8 @@ typeof navigator === "object" && (function (global, factory) {
global_1.addEventListener &&
typeof postMessage == 'function' &&
!global_1.importScripts &&
!fails(post) &&
location.protocol !== 'file:'
location && location.protocol !== 'file:' &&
!fails(post)
) {
defer = post;
global_1.addEventListener('message', listener, false);
@@ -6075,14 +6110,14 @@ typeof navigator === "object" && (function (global, factory) {
};
var getOwnPropertyDescriptor$3 = objectGetOwnPropertyDescriptor.f;
var macrotask = task.set;
var MutationObserver$1 = global_1.MutationObserver || global_1.WebKitMutationObserver;
var document$2 = global_1.document;
var process$2 = global_1.process;
var Promise$1 = global_1.Promise;
var IS_NODE = classofRaw(process$2) == 'process';
// Node.js 11 shows ExperimentalWarning on getting `queueMicrotask`
var queueMicrotaskDescriptor = getOwnPropertyDescriptor$3(global_1, 'queueMicrotask');
var queueMicrotask = queueMicrotaskDescriptor && queueMicrotaskDescriptor.value;
@@ -6093,7 +6128,7 @@ typeof navigator === "object" && (function (global, factory) {
if (!queueMicrotask) {
flush = function () {
var parent, fn;
if (IS_NODE && (parent = process$2.domain)) parent.exit();
if (engineIsNode && (parent = process$2.domain)) parent.exit();
while (head) {
fn = head.fn;
head = head.next;
@@ -6108,15 +6143,10 @@ typeof navigator === "object" && (function (global, factory) {
if (parent) parent.enter();
};
// Node.js
if (IS_NODE) {
notify = function () {
process$2.nextTick(flush);
};
// browsers with MutationObserver, except iOS - https://github.com/zloirock/core-js/issues/339
} else if (MutationObserver$1 && !engineIsIos) {
if (!engineIsIos && !engineIsNode && MutationObserver$1 && document$2) {
toggle = true;
node = document.createTextNode('');
node = document$2.createTextNode('');
new MutationObserver$1(flush).observe(node, { characterData: true });
notify = function () {
node.data = toggle = !toggle;
@@ -6129,6 +6159,11 @@ typeof navigator === "object" && (function (global, factory) {
notify = function () {
then.call(promise, flush);
};
// Node.js without promises
} else if (engineIsNode) {
notify = function () {
process$2.nextTick(flush);
};
// for other environments - macrotask based on:
// - setImmediate
// - MessageChannel
@@ -6207,6 +6242,7 @@ typeof navigator === "object" && (function (global, factory) {
var SPECIES$6 = wellKnownSymbol('species');
var PROMISE = 'Promise';
var getInternalState$3 = internalState.get;
@@ -6214,13 +6250,13 @@ typeof navigator === "object" && (function (global, factory) {
var getInternalPromiseState = internalState.getterFor(PROMISE);
var PromiseConstructor = nativePromiseConstructor;
var TypeError$1 = global_1.TypeError;
var document$2 = global_1.document;
var document$3 = global_1.document;
var process$3 = global_1.process;
var $fetch$1 = getBuiltIn('fetch');
var newPromiseCapability$1 = newPromiseCapability.f;
var newGenericPromiseCapability = newPromiseCapability$1;
var IS_NODE$1 = classofRaw(process$3) == 'process';
var DISPATCH_EVENT = !!(document$2 && document$2.createEvent && global_1.dispatchEvent);
var DISPATCH_EVENT = !!(document$3 && document$3.createEvent && global_1.dispatchEvent);
var NATIVE_REJECTION_EVENT = typeof PromiseRejectionEvent == 'function';
var UNHANDLED_REJECTION = 'unhandledrejection';
var REJECTION_HANDLED = 'rejectionhandled';
var PENDING = 0;
@@ -6238,7 +6274,7 @@ typeof navigator === "object" && (function (global, factory) {
// We can't detect it synchronously, so just check versions
if (engineV8Version === 66) return true;
// Unhandled rejections tracking support, NodeJS Promise without it fails @@species test
if (!IS_NODE$1 && typeof PromiseRejectionEvent != 'function') return true;
if (!engineIsNode && !NATIVE_REJECTION_EVENT) return true;
}
// We can't use @@species feature detection in V8 since it causes
// deoptimization and performance degradation
@@ -6264,7 +6300,7 @@ typeof navigator === "object" && (function (global, factory) {
return isObject(it) && typeof (then = it.then) == 'function' ? then : false;
};
var notify$1 = function (promise, state, isReject) {
var notify$1 = function (state, isReject) {
if (state.notified) return;
state.notified = true;
var chain = state.reactions;
@@ -6283,7 +6319,7 @@ typeof navigator === "object" && (function (global, factory) {
try {
if (handler) {
if (!ok) {
if (state.rejection === UNHANDLED) onHandleUnhandled(promise, state);
if (state.rejection === UNHANDLED) onHandleUnhandled(state);
state.rejection = HANDLED;
}
if (handler === true) result = value;
@@ -6308,36 +6344,37 @@ typeof navigator === "object" && (function (global, factory) {
}
state.reactions = [];
state.notified = false;
if (isReject && !state.rejection) onUnhandled(promise, state);
if (isReject && !state.rejection) onUnhandled(state);
});
};
var dispatchEvent = function (name, promise, reason) {
var event, handler;
if (DISPATCH_EVENT) {
event = document$2.createEvent('Event');
event = document$3.createEvent('Event');
event.promise = promise;
event.reason = reason;
event.initEvent(name, false, true);
global_1.dispatchEvent(event);
} else event = { promise: promise, reason: reason };
if (handler = global_1['on' + name]) handler(event);
if (!NATIVE_REJECTION_EVENT && (handler = global_1['on' + name])) handler(event);
else if (name === UNHANDLED_REJECTION) hostReportErrors('Unhandled promise rejection', reason);
};
var onUnhandled = function (promise, state) {
var onUnhandled = function (state) {
task$1.call(global_1, function () {
var promise = state.facade;
var value = state.value;
var IS_UNHANDLED = isUnhandled(state);
var result;
if (IS_UNHANDLED) {
result = perform(function () {
if (IS_NODE$1) {
if (engineIsNode) {
process$3.emit('unhandledRejection', value, promise);
} else dispatchEvent(UNHANDLED_REJECTION, promise, value);
});
// Browsers should not trigger `rejectionHandled` event if it was handled here, NodeJS - should
state.rejection = IS_NODE$1 || isUnhandled(state) ? UNHANDLED : HANDLED;
state.rejection = engineIsNode || isUnhandled(state) ? UNHANDLED : HANDLED;
if (result.error) throw result.value;
}
});
@@ -6347,55 +6384,56 @@ typeof navigator === "object" && (function (global, factory) {
return state.rejection !== HANDLED && !state.parent;
};
var onHandleUnhandled = function (promise, state) {
var onHandleUnhandled = function (state) {
task$1.call(global_1, function () {
if (IS_NODE$1) {
var promise = state.facade;
if (engineIsNode) {
process$3.emit('rejectionHandled', promise);
} else dispatchEvent(REJECTION_HANDLED, promise, state.value);
});
};
var bind = function (fn, promise, state, unwrap) {
var bind = function (fn, state, unwrap) {
return function (value) {
fn(promise, state, value, unwrap);
fn(state, value, unwrap);
};
};
var internalReject = function (promise, state, value, unwrap) {
var internalReject = function (state, value, unwrap) {
if (state.done) return;
state.done = true;
if (unwrap) state = unwrap;
state.value = value;
state.state = REJECTED;
notify$1(promise, state, true);
notify$1(state, true);
};
var internalResolve = function (promise, state, value, unwrap) {
var internalResolve = function (state, value, unwrap) {
if (state.done) return;
state.done = true;
if (unwrap) state = unwrap;
try {
if (promise === value) throw TypeError$1("Promise can't be resolved itself");
if (state.facade === value) throw TypeError$1("Promise can't be resolved itself");
var then = isThenable(value);
if (then) {
microtask(function () {
var wrapper = { done: false };
try {
then.call(value,
bind(internalResolve, promise, wrapper, state),
bind(internalReject, promise, wrapper, state)
bind(internalResolve, wrapper, state),
bind(internalReject, wrapper, state)
);
} catch (error) {
internalReject(promise, wrapper, error, state);
internalReject(wrapper, error, state);
}
});
} else {
state.value = value;
state.state = FULFILLED;
notify$1(promise, state, false);
notify$1(state, false);
}
} catch (error) {
internalReject(promise, { done: false }, error, state);
internalReject({ done: false }, error, state);
}
};
@@ -6408,9 +6446,9 @@ typeof navigator === "object" && (function (global, factory) {
Internal.call(this);
var state = getInternalState$3(this);
try {
executor(bind(internalResolve, this, state), bind(internalReject, this, state));
executor(bind(internalResolve, state), bind(internalReject, state));
} catch (error) {
internalReject(this, state, error);
internalReject(state, error);
}
};
// eslint-disable-next-line no-unused-vars
@@ -6434,10 +6472,10 @@ typeof navigator === "object" && (function (global, factory) {
var reaction = newPromiseCapability$1(speciesConstructor(this, PromiseConstructor));
reaction.ok = typeof onFulfilled == 'function' ? onFulfilled : true;
reaction.fail = typeof onRejected == 'function' && onRejected;
reaction.domain = IS_NODE$1 ? process$3.domain : undefined;
reaction.domain = engineIsNode ? process$3.domain : undefined;
state.parent = true;
state.reactions.push(reaction);
if (state.state != PENDING) notify$1(this, state, false);
if (state.state != PENDING) notify$1(state, false);
return reaction.promise;
},
// `Promise.prototype.catch` method
@@ -6450,8 +6488,8 @@ typeof navigator === "object" && (function (global, factory) {
var promise = new Internal();
var state = getInternalState$3(promise);
this.promise = promise;
this.resolve = bind(internalResolve, promise, state);
this.reject = bind(internalReject, promise, state);
this.resolve = bind(internalResolve, state);
this.reject = bind(internalReject, state);
};
newPromiseCapability.f = newPromiseCapability$1 = function (C) {
return C === PromiseConstructor || C === PromiseWrapper
@@ -6522,7 +6560,7 @@ typeof navigator === "object" && (function (global, factory) {
var values = [];
var counter = 0;
var remaining = 1;
iterate_1(iterable, function (promise) {
iterate(iterable, function (promise) {
var index = counter++;
var alreadyCalled = false;
values.push(undefined);
@@ -6547,7 +6585,7 @@ typeof navigator === "object" && (function (global, factory) {
var reject = capability.reject;
var result = perform(function () {
var $promiseResolve = aFunction$1(C.resolve);
iterate_1(iterable, function (promise) {
iterate(iterable, function (promise) {
$promiseResolve.call(C, promise).then(capability.resolve, reject);
});
});
@@ -6794,12 +6832,17 @@ typeof navigator === "object" && (function (global, factory) {
var STRICT_METHOD$5 = arrayMethodIsStrict('reduce');
var USES_TO_LENGTH$9 = arrayMethodUsesToLength('reduce', { 1: 0 });
// Chrome 80-82 has a critical bug
// https://bugs.chromium.org/p/chromium/issues/detail?id=1049982
var CHROME_BUG = !engineIsNode && engineV8Version > 79 && engineV8Version < 83;
// `Array.prototype.reduce` method
// https://tc39.github.io/ecma262/#sec-array.prototype.reduce
_export({ target: 'Array', proto: true, forced: !STRICT_METHOD$5 || !USES_TO_LENGTH$9 }, {
_export({ target: 'Array', proto: true, forced: !STRICT_METHOD$5 || !USES_TO_LENGTH$9 || CHROME_BUG }, {
reduce: function reduce(callbackfn /* , initialValue */) {
return $reduce(this, callbackfn, arguments.length, arguments.length > 1 ? arguments[1] : undefined);
}
@@ -7433,7 +7476,12 @@ typeof navigator === "object" && (function (global, factory) {
if (this.isVimeo && !this.config.vimeo.premium && this.supported.ui) {
var height = 100 / this.media.offsetWidth * parseInt(window.getComputedStyle(this.media).paddingBottom, 10);
var offset = (height - padding) / (height / 50);
this.media.style.transform = "translateY(-".concat(offset, "%)");
if (this.fullscreen.active) {
wrapper.style.paddingBottom = null;
} else {
this.media.style.transform = "translateY(-".concat(offset, "%)");
}
} else if (this.isHTML5) {
wrapper.classList.toggle(this.config.classNames.videoFixedRatio, ratio !== null);
}
@@ -9975,7 +10023,7 @@ typeof navigator === "object" && (function (global, factory) {
// Sprite (for icons)
loadSprite: true,
iconPrefix: 'plyr',
iconUrl: 'https://cdn.plyr.io/3.6.2/plyr.svg',
iconUrl: 'https://cdn.plyr.io/3.6.3/plyr.svg',
// Blank video (used to prevent errors on source change)
blankVideo: 'https://cdn.plyr.io/static/blank.mp4',
// Quality default
@@ -10093,7 +10141,7 @@ typeof navigator === "object" && (function (global, factory) {
vimeo: {
sdk: 'https://player.vimeo.com/api/player.js',
iframe: 'https://player.vimeo.com/video/{0}?{1}',
api: 'https://vimeo.com/api/v2/video/{0}.json'
api: 'https://vimeo.com/api/oembed.json?url={0}'
},
youtube: {
sdk: 'https://www.youtube.com/iframe_api',
@@ -10263,24 +10311,27 @@ typeof navigator === "object" && (function (global, factory) {
title: false,
speed: true,
transparent: false,
// Custom settings from Plyr
customControls: true,
referrerPolicy: null,
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/referrerPolicy
// Whether the owner of the video has a Pro or Business account
// (which allows us to properly hide controls without CSS hacks, etc)
premium: false,
// Custom settings from Plyr
referrerPolicy: null // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/referrerPolicy
premium: false
},
// YouTube plugin
youtube: {
noCookie: true,
// Whether to use an alternative version of YouTube without cookies
rel: 0,
// No related vids
showinfo: 0,
// Hide info
iv_load_policy: 3,
// Hide annotations
modestbranding: 1 // Hide logos as much as possible (they still show one in the corner when paused)
modestbranding: 1,
// Hide logos as much as possible (they still show one in the corner when paused)
// Custom settings from Plyr
customControls: true,
noCookie: false // Whether to use an alternative version of YouTube without cookies
}
};
@@ -10399,7 +10450,7 @@ typeof navigator === "object" && (function (global, factory) {
return;
}
_this.toggle();
_this.player.listeners.proxy(event, _this.toggle, 'fullscreen');
}); // Tap focus when in fullscreen
on.call(this, this.player.elements.container, 'keydown', function (event) {
@@ -10422,10 +10473,12 @@ typeof navigator === "object" && (function (global, factory) {
if (is$1.element(button)) {
button.pressed = this.active;
} // Trigger an event
} // Always trigger events on the plyr / media element (not a fullscreen container) and let them bubble up
triggerEvent.call(this.player, this.target, this.active ? 'enterfullscreen' : 'exitfullscreen', true);
var target = this.target === this.player.media ? this.target : this.player.elements.container; // Trigger an event
triggerEvent.call(this.player, target, this.active ? 'enterfullscreen' : 'exitfullscreen', true);
}
}, {
key: "toggleFallback",
@@ -10820,7 +10873,9 @@ typeof navigator === "object" && (function (global, factory) {
} // Set property synchronously to respect the call order
this.media.setAttribute('data-poster', poster); // Wait until ui is ready
this.media.setAttribute('data-poster', poster); // Show the poster
this.elements.poster.removeAttribute('hidden'); // Wait until ui is ready
return ready.call(this) // Load image
.then(function () {
@@ -10904,7 +10959,7 @@ typeof navigator === "object" && (function (global, factory) {
// Loop through values (as they are the keys when the object is spread 🤔)
Object.values(_objectSpread2({}, this.media.style)) // We're only fussed about Plyr specific properties
.filter(function (key) {
return !is$1.empty(key) && key.startsWith('--plyr');
return !is$1.empty(key) && is$1.string(key) && key.startsWith('--plyr');
}).forEach(function (key) {
// Set on the container
_this5.elements.container.style.setProperty(key, _this5.media.style.getPropertyValue(key)); // Clean up from media element
@@ -11252,7 +11307,14 @@ typeof navigator === "object" && (function (global, factory) {
ratio = _setPlayerSize.ratio; // Set Vimeo gutter
setGutter(ratio, padding, isEnter); // If not using native browser fullscreen API, we need to check for resizes of viewport
setGutter(ratio, padding, isEnter); // Horrible hack for Safari 14 not repainting properly on entering fullscreen
if (isEnter) {
setTimeout(function () {
return repaint(elements.container);
}, 100);
} // If not using native browser fullscreen API, we need to check for resizes of viewport
if (!usingNative) {
if (isEnter) {
@@ -11443,9 +11505,17 @@ typeof navigator === "object" && (function (global, factory) {
this.bind(elements.buttons.restart, 'click', player.restart, 'restart'); // Rewind
this.bind(elements.buttons.rewind, 'click', player.rewind, 'rewind'); // Rewind
this.bind(elements.buttons.rewind, 'click', function () {
// Record seek time so we can prevent hiding controls for a few seconds after rewind
player.lastSeekTime = Date.now();
player.rewind();
}, 'rewind'); // Rewind
this.bind(elements.buttons.fastForward, 'click', player.forward, 'fastForward'); // Mute toggle
this.bind(elements.buttons.fastForward, 'click', function () {
// Record seek time so we can prevent hiding controls for a few seconds after fast forward
player.lastSeekTime = Date.now();
player.forward();
}, 'fastForward'); // Mute toggle
this.bind(elements.buttons.mute, 'click', function () {
player.muted = !player.muted;
@@ -12153,35 +12223,32 @@ typeof navigator === "object" && (function (global, factory) {
} // Inject the package
var poster = player.poster;
if (premium) {
iframe.setAttribute('data-poster', poster);
if (premium || !config.customControls) {
iframe.setAttribute('data-poster', player.poster);
player.media = replaceElement(iframe, player.media);
} else {
var wrapper = createElement('div', {
class: player.config.classNames.embedContainer,
'data-poster': poster
'data-poster': player.poster
});
wrapper.appendChild(iframe);
player.media = replaceElement(wrapper, player.media);
} // Get poster image
fetch(format(player.config.urls.vimeo.api, id), 'json').then(function (response) {
if (is$1.empty(response)) {
return;
} // Get the URL for thumbnail
if (!config.customControls) {
fetch(format(player.config.urls.vimeo.api, src)).then(function (response) {
if (is$1.empty(response) || !response.thumbnail_url) {
return;
} // Set and show poster
var url = new URL(response[0].thumbnail_large); // Get original image
url.pathname = "".concat(url.pathname.split('_')[0], ".jpg"); // Set and show poster
ui.setPoster.call(player, url.href).catch(function () {});
}); // Setup instance
ui.setPoster.call(player, response.thumbnail_url).catch(function () {});
});
} // Setup instance
// https://github.com/vimeo/player.js
player.embed = new window.Vimeo.Player(iframe, {
autopause: player.config.autopause,
muted: player.muted
@@ -12421,9 +12488,11 @@ typeof navigator === "object" && (function (global, factory) {
triggerEvent.call(player, player.media, 'error');
}); // Rebuild UI
setTimeout(function () {
return ui.build.call(player);
}, 0);
if (config.customControls) {
setTimeout(function () {
return ui.build.call(player);
}, 0);
}
}
};
@@ -12514,7 +12583,8 @@ typeof navigator === "object" && (function (global, factory) {
},
// API ready
ready: function ready() {
var player = this; // Ignore already setup (race condition)
var player = this;
var config = player.config.youtube; // Ignore already setup (race condition)
var currentId = player.media && player.media.getAttribute('id');
@@ -12531,53 +12601,53 @@ typeof navigator === "object" && (function (global, factory) {
var videoId = parseId$1(source);
var id = generateId(player.provider); // Get poster, if already set
var poster = player.poster; // Replace media element
var id = generateId(player.provider); // Replace media element
var container = createElement('div', {
id: id,
'data-poster': poster
'data-poster': config.customControls ? player.poster : undefined
});
player.media = replaceElement(container, player.media); // Id to poster wrapper
player.media = replaceElement(container, player.media); // Only load the poster when using custom controls
var posterSrc = function posterSrc(s) {
return "https://i.ytimg.com/vi/".concat(videoId, "/").concat(s, "default.jpg");
}; // Check thumbnail images in order of quality, but reject fallback thumbnails (120px wide)
if (config.customControls) {
var posterSrc = function posterSrc(s) {
return "https://i.ytimg.com/vi/".concat(videoId, "/").concat(s, "default.jpg");
}; // Check thumbnail images in order of quality, but reject fallback thumbnails (120px wide)
loadImage(posterSrc('maxres'), 121) // Higest quality and unpadded
.catch(function () {
return loadImage(posterSrc('sd'), 121);
}) // 480p padded 4:3
.catch(function () {
return loadImage(posterSrc('hq'));
}) // 360p padded 4:3. Always exists
.then(function (image) {
return ui.setPoster.call(player, image.src);
}).then(function (src) {
// If the image is padded, use background-size "cover" instead (like youtube does too with their posters)
if (!src.includes('maxres')) {
player.elements.poster.style.backgroundSize = 'cover';
}
}).catch(function () {});
var config = player.config.youtube; // Setup instance
loadImage(posterSrc('maxres'), 121) // Higest quality and unpadded
.catch(function () {
return loadImage(posterSrc('sd'), 121);
}) // 480p padded 4:3
.catch(function () {
return loadImage(posterSrc('hq'));
}) // 360p padded 4:3. Always exists
.then(function (image) {
return ui.setPoster.call(player, image.src);
}).then(function (src) {
// If the image is padded, use background-size "cover" instead (like youtube does too with their posters)
if (!src.includes('maxres')) {
player.elements.poster.style.backgroundSize = 'cover';
}
}).catch(function () {});
} // Setup instance
// https://developers.google.com/youtube/iframe_api_reference
player.embed = new window.YT.Player(id, {
player.embed = new window.YT.Player(player.media, {
videoId: videoId,
host: getHost$1(config),
playerVars: extend({}, {
autoplay: player.config.autoplay ? 1 : 0,
// Autoplay
hl: player.config.hl,
autoplay: player.config.autoplay ? 1 : 0,
// iframe interface language
controls: player.supported.ui ? 0 : 1,
// Only show controls if not fully supported
disablekb: 1,
hl: player.config.hl,
// Only show controls if not fully supported or opted out
controls: player.supported.ui && config.customControls ? 0 : 1,
// Disable keyboard as we handle it
playsinline: !player.config.fullscreen.iosNative ? 1 : 0,
disablekb: 1,
// Allow iOS inline playback
playsinline: !player.config.fullscreen.iosNative ? 1 : 0,
// Captions are flaky on YouTube
cc_load_policy: player.captions.active ? 1 : 0,
cc_lang_pref: player.config.captions.language,
@@ -12688,6 +12758,7 @@ typeof navigator === "object" && (function (global, factory) {
var toggle = is$1.boolean(input) ? input : muted;
muted = toggle;
instance[toggle ? 'mute' : 'unMute']();
instance.setVolume(volume * 100);
triggerEvent.call(player, player.media, 'volumechange');
}
}); // Source
@@ -12710,7 +12781,7 @@ typeof navigator === "object" && (function (global, factory) {
return player.config.speed.options.includes(s);
}); // Set the tabindex to avoid focus entering iframe
if (player.supported.ui) {
if (player.supported.ui && config.customControls) {
player.media.setAttribute('tabindex', -1);
}
@@ -12737,9 +12808,11 @@ typeof navigator === "object" && (function (global, factory) {
}
}, 200); // Rebuild UI
setTimeout(function () {
return ui.build.call(player);
}, 50);
if (config.customControls) {
setTimeout(function () {
return ui.build.call(player);
}, 50);
}
},
onStateChange: function onStateChange(event) {
// Get the instance
@@ -12785,7 +12858,7 @@ typeof navigator === "object" && (function (global, factory) {
case 1:
// Restore paused state (YouTube starts playing on seek if the video hasn't been played yet)
if (!player.config.autoplay && player.media.paused && !player.embed.hasPlayed) {
if (config.customControls && !player.config.autoplay && player.media.paused && !player.embed.hasPlayed) {
player.media.pause();
} else {
assurePlaybackState$1.call(player, true);
@@ -12858,7 +12931,8 @@ typeof navigator === "object" && (function (global, factory) {
wrap$1(this.media, this.elements.wrapper); // Poster image container
this.elements.poster = createElement('div', {
class: this.config.classNames.poster
class: this.config.classNames.poster,
hidden: ''
});
this.elements.wrapper.appendChild(this.elements.poster);
}
@@ -14726,9 +14800,9 @@ typeof navigator === "object" && (function (global, factory) {
if (this.isHTML5 && this.config.autoplay) {
setTimeout(function () {
this.once('canplay', function () {
return silencePromise(_this.play());
}, 10);
});
} // Seek time will be recorded (in listeners.js) so we can prevent hiding controls for a few seconds after seek
@@ -15017,7 +15091,9 @@ typeof navigator === "object" && (function (global, factory) {
}
} else {
// Unbind listeners
unbindListeners.call(_this3); // Replace the container with the original element provided
unbindListeners.call(_this3); // Cancel current network requests
html5.cancelRequests.call(_this3); // Replace the container with the original element provided
replaceElement(_this3.elements.original, _this3.elements.container); // Event
+2 -2
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+2 -2
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+228 -152
View File
@@ -1,4 +1,4 @@
typeof navigator === "object" && // Polyfill for creating CustomEvents on IE9/10/11
// Polyfill for creating CustomEvents on IE9/10/11
// code pulled from:
// https://github.com/d4tocchini/customevent-polyfill
// https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent#Polyfill
@@ -68,7 +68,7 @@ var global_1 =
check(typeof self == 'object' && self) ||
check(typeof commonjsGlobal == 'object' && commonjsGlobal) ||
// eslint-disable-next-line no-new-func
Function('return this')();
(function () { return this; })() || Function('return this')();
var fails = function (exec) {
try {
@@ -263,7 +263,7 @@ var shared = createCommonjsModule(function (module) {
(module.exports = function (key, value) {
return sharedStore[key] || (sharedStore[key] = value !== undefined ? value : {});
})('versions', []).push({
version: '3.6.5',
version: '3.7.0',
mode: 'global',
copyright: '© 2020 Denis Pushkarev (zloirock.ru)'
});
@@ -301,11 +301,12 @@ var getterFor = function (TYPE) {
};
if (nativeWeakMap) {
var store$1 = new WeakMap$2();
var store$1 = sharedStore.state || (sharedStore.state = new WeakMap$2());
var wmget = store$1.get;
var wmhas = store$1.has;
var wmset = store$1.set;
set = function (it, metadata) {
metadata.facade = it;
wmset.call(store$1, it, metadata);
return metadata;
};
@@ -319,6 +320,7 @@ if (nativeWeakMap) {
var STATE = sharedKey('state');
hiddenKeys[STATE] = true;
set = function (it, metadata) {
metadata.facade = it;
createNonEnumerableProperty(it, STATE, metadata);
return metadata;
};
@@ -347,9 +349,15 @@ var TEMPLATE = String(String).split('String');
var unsafe = options ? !!options.unsafe : false;
var simple = options ? !!options.enumerable : false;
var noTargetGet = options ? !!options.noTargetGet : false;
var state;
if (typeof value == 'function') {
if (typeof key == 'string' && !has(value, 'name')) createNonEnumerableProperty(value, 'name', key);
enforceInternalState(value).source = TEMPLATE.join(typeof key == 'string' ? key : '');
if (typeof key == 'string' && !has(value, 'name')) {
createNonEnumerableProperty(value, 'name', key);
}
state = enforceInternalState(value);
if (!state.source) {
state.source = TEMPLATE.join(typeof key == 'string' ? key : '');
}
}
if (O === global_1) {
if (simple) O[key] = value;
@@ -2435,14 +2443,20 @@ var objectAssign = !nativeAssign || fails(function () {
} return T;
} : nativeAssign;
var iteratorClose = function (iterator) {
var returnMethod = iterator['return'];
if (returnMethod !== undefined) {
return anObject(returnMethod.call(iterator)).value;
}
};
// call something on iterator step with safe closing on error
var callWithSafeIterationClosing = function (iterator, fn, value, ENTRIES) {
try {
return ENTRIES ? fn(anObject(value)[0], value[1]) : fn(value);
// 7.4.6 IteratorClose(iterator, completion)
} catch (error) {
var returnMethod = iterator['return'];
if (returnMethod !== undefined) anObject(returnMethod.call(iterator));
iteratorClose(iterator);
throw error;
}
};
@@ -2839,7 +2853,7 @@ var URLSearchParamsConstructor = function URLSearchParams(/* init */) {
var URLSearchParamsPrototype = URLSearchParamsConstructor.prototype;
redefineAll(URLSearchParamsPrototype, {
// `URLSearchParams.prototype.appent` method
// `URLSearchParams.prototype.append` method
// https://url.spec.whatwg.org/#dom-urlsearchparams-append
append: function append(name, value) {
validateArgumentsLength(arguments.length, 2);
@@ -4402,7 +4416,7 @@ function _nonIterableRest() {
var checkIfURLSearchParamsSupported = function checkIfURLSearchParamsSupported() {
try {
var URLSearchParams = global.URLSearchParams;
return new URLSearchParams('?a=1').toString() === 'a=1' && typeof URLSearchParams.prototype.set === 'function';
return new URLSearchParams('?a=1').toString() === 'a=1' && typeof URLSearchParams.prototype.set === 'function' && typeof URLSearchParams.prototype.entries === 'function';
} catch (e) {
return false;
}
@@ -4500,12 +4514,14 @@ function _nonIterableRest() {
var _URL = global.URL;
var URL = function URL(url, base) {
if (typeof url !== 'string') url = String(url); // Only create another document if the base is different from current location.
if (typeof url !== 'string') url = String(url);
if (base && typeof base !== 'string') base = String(base); // Only create another document if the base is different from current location.
var doc = document,
baseElement;
if (base && (global.location === void 0 || base !== global.location.href)) {
base = base.toLowerCase();
doc = document.implementation.createHTMLDocument('');
baseElement = doc.createElement('base');
baseElement.href = base;
@@ -4526,7 +4542,11 @@ function _nonIterableRest() {
anchorElement.href = anchorElement.href; // force href to refresh
}
if (anchorElement.protocol === ':' || !/:/.test(anchorElement.href)) {
var inputElement = doc.createElement('input');
inputElement.type = 'url';
inputElement.value = url;
if (anchorElement.protocol === ':' || !/:/.test(anchorElement.href) || !inputElement.checkValidity() && !base) {
throw new TypeError('Invalid URL');
}
@@ -5007,11 +5027,11 @@ var correctIsRegexpLogic = function (METHOD_NAME) {
var regexp = /./;
try {
'/./'[METHOD_NAME](regexp);
} catch (e) {
} catch (error1) {
try {
regexp[MATCH$1] = false;
return '/./'[METHOD_NAME](regexp);
} catch (f) { /* empty */ }
} catch (error2) { /* empty */ }
} return false;
};
@@ -5093,16 +5113,31 @@ var internalMetadata_2 = internalMetadata.fastKey;
var internalMetadata_3 = internalMetadata.getWeakData;
var internalMetadata_4 = internalMetadata.onFreeze;
var iterate_1 = createCommonjsModule(function (module) {
var Result = function (stopped, result) {
this.stopped = stopped;
this.result = result;
};
var iterate = module.exports = function (iterable, fn, that, AS_ENTRIES, IS_ITERATOR) {
var boundFunction = functionBindContext(fn, that, AS_ENTRIES ? 2 : 1);
var iterate = function (iterable, unboundFunction, options) {
var that = options && options.that;
var AS_ENTRIES = !!(options && options.AS_ENTRIES);
var IS_ITERATOR = !!(options && options.IS_ITERATOR);
var INTERRUPTED = !!(options && options.INTERRUPTED);
var fn = functionBindContext(unboundFunction, that, 1 + AS_ENTRIES + INTERRUPTED);
var iterator, iterFn, index, length, result, next, step;
var stop = function (condition) {
if (iterator) iteratorClose(iterator);
return new Result(true, condition);
};
var callFn = function (value) {
if (AS_ENTRIES) {
anObject(value);
return INTERRUPTED ? fn(value[0], value[1], stop) : fn(value[0], value[1]);
} return INTERRUPTED ? fn(value, stop) : fn(value);
};
if (IS_ITERATOR) {
iterator = iterable;
} else {
@@ -5111,9 +5146,7 @@ var iterate = module.exports = function (iterable, fn, that, AS_ENTRIES, IS_ITER
// optimisation for array iterators
if (isArrayIteratorMethod(iterFn)) {
for (index = 0, length = toLength(iterable.length); length > index; index++) {
result = AS_ENTRIES
? boundFunction(anObject(step = iterable[index])[0], step[1])
: boundFunction(iterable[index]);
result = callFn(iterable[index]);
if (result && result instanceof Result) return result;
} return new Result(false);
}
@@ -5122,16 +5155,16 @@ var iterate = module.exports = function (iterable, fn, that, AS_ENTRIES, IS_ITER
next = iterator.next;
while (!(step = next.call(iterator)).done) {
result = callWithSafeIterationClosing(iterator, boundFunction, step.value, AS_ENTRIES);
try {
result = callFn(step.value);
} catch (error) {
iteratorClose(iterator);
throw error;
}
if (typeof result == 'object' && result && result instanceof Result) return result;
} return new Result(false);
};
iterate.stop = function (result) {
return new Result(true, result);
};
});
var collection = function (CONSTRUCTOR_NAME, wrapper, common) {
var IS_MAP = CONSTRUCTOR_NAME.indexOf('Map') !== -1;
var IS_WEAK = CONSTRUCTOR_NAME.indexOf('Weak') !== -1;
@@ -5189,7 +5222,7 @@ var collection = function (CONSTRUCTOR_NAME, wrapper, common) {
Constructor = wrapper(function (dummy, iterable) {
anInstance(dummy, Constructor, CONSTRUCTOR_NAME);
var that = inheritIfRequired(new NativeConstructor(), dummy, Constructor);
if (iterable != undefined) iterate_1(iterable, that[ADDER], that, IS_MAP);
if (iterable != undefined) iterate(iterable, that[ADDER], { that: that, AS_ENTRIES: IS_MAP });
return that;
});
Constructor.prototype = NativePrototype;
@@ -5279,7 +5312,7 @@ var collectionWeak = {
id: id$1++,
frozen: undefined
});
if (iterable != undefined) iterate_1(iterable, that[ADDER], that, IS_MAP);
if (iterable != undefined) iterate(iterable, that[ADDER], { that: that, AS_ENTRIES: IS_MAP });
});
var getInternalState = internalStateGetterFor(CONSTRUCTOR_NAME);
@@ -5968,6 +6001,8 @@ var setSpecies = function (CONSTRUCTOR_NAME) {
var engineIsIos = /(iphone|ipod|ipad).*applewebkit/i.test(engineUserAgent);
var engineIsNode = classofRaw(global_1.process) == 'process';
var location = global_1.location;
var set$1 = global_1.setImmediate;
var clear = global_1.clearImmediate;
@@ -6020,7 +6055,7 @@ if (!set$1 || !clear) {
delete queue[id];
};
// Node.js 0.8-
if (classofRaw(process$1) == 'process') {
if (engineIsNode) {
defer = function (id) {
process$1.nextTick(runner(id));
};
@@ -6042,8 +6077,8 @@ if (!set$1 || !clear) {
global_1.addEventListener &&
typeof postMessage == 'function' &&
!global_1.importScripts &&
!fails(post) &&
location.protocol !== 'file:'
location && location.protocol !== 'file:' &&
!fails(post)
) {
defer = post;
global_1.addEventListener('message', listener, false);
@@ -6069,14 +6104,14 @@ var task = {
};
var getOwnPropertyDescriptor$3 = objectGetOwnPropertyDescriptor.f;
var macrotask = task.set;
var MutationObserver$1 = global_1.MutationObserver || global_1.WebKitMutationObserver;
var document$2 = global_1.document;
var process$2 = global_1.process;
var Promise$1 = global_1.Promise;
var IS_NODE = classofRaw(process$2) == 'process';
// Node.js 11 shows ExperimentalWarning on getting `queueMicrotask`
var queueMicrotaskDescriptor = getOwnPropertyDescriptor$3(global_1, 'queueMicrotask');
var queueMicrotask = queueMicrotaskDescriptor && queueMicrotaskDescriptor.value;
@@ -6087,7 +6122,7 @@ var flush, head, last, notify, toggle, node, promise, then;
if (!queueMicrotask) {
flush = function () {
var parent, fn;
if (IS_NODE && (parent = process$2.domain)) parent.exit();
if (engineIsNode && (parent = process$2.domain)) parent.exit();
while (head) {
fn = head.fn;
head = head.next;
@@ -6102,15 +6137,10 @@ if (!queueMicrotask) {
if (parent) parent.enter();
};
// Node.js
if (IS_NODE) {
notify = function () {
process$2.nextTick(flush);
};
// browsers with MutationObserver, except iOS - https://github.com/zloirock/core-js/issues/339
} else if (MutationObserver$1 && !engineIsIos) {
if (!engineIsIos && !engineIsNode && MutationObserver$1 && document$2) {
toggle = true;
node = document.createTextNode('');
node = document$2.createTextNode('');
new MutationObserver$1(flush).observe(node, { characterData: true });
notify = function () {
node.data = toggle = !toggle;
@@ -6123,6 +6153,11 @@ if (!queueMicrotask) {
notify = function () {
then.call(promise, flush);
};
// Node.js without promises
} else if (engineIsNode) {
notify = function () {
process$2.nextTick(flush);
};
// for other environments - macrotask based on:
// - setImmediate
// - MessageChannel
@@ -6201,6 +6236,7 @@ var task$1 = task.set;
var SPECIES$6 = wellKnownSymbol('species');
var PROMISE = 'Promise';
var getInternalState$3 = internalState.get;
@@ -6208,13 +6244,13 @@ var setInternalState$6 = internalState.set;
var getInternalPromiseState = internalState.getterFor(PROMISE);
var PromiseConstructor = nativePromiseConstructor;
var TypeError$1 = global_1.TypeError;
var document$2 = global_1.document;
var document$3 = global_1.document;
var process$3 = global_1.process;
var $fetch$1 = getBuiltIn('fetch');
var newPromiseCapability$1 = newPromiseCapability.f;
var newGenericPromiseCapability = newPromiseCapability$1;
var IS_NODE$1 = classofRaw(process$3) == 'process';
var DISPATCH_EVENT = !!(document$2 && document$2.createEvent && global_1.dispatchEvent);
var DISPATCH_EVENT = !!(document$3 && document$3.createEvent && global_1.dispatchEvent);
var NATIVE_REJECTION_EVENT = typeof PromiseRejectionEvent == 'function';
var UNHANDLED_REJECTION = 'unhandledrejection';
var REJECTION_HANDLED = 'rejectionhandled';
var PENDING = 0;
@@ -6232,7 +6268,7 @@ var FORCED$3 = isForced_1(PROMISE, function () {
// We can't detect it synchronously, so just check versions
if (engineV8Version === 66) return true;
// Unhandled rejections tracking support, NodeJS Promise without it fails @@species test
if (!IS_NODE$1 && typeof PromiseRejectionEvent != 'function') return true;
if (!engineIsNode && !NATIVE_REJECTION_EVENT) return true;
}
// We can't use @@species feature detection in V8 since it causes
// deoptimization and performance degradation
@@ -6258,7 +6294,7 @@ var isThenable = function (it) {
return isObject(it) && typeof (then = it.then) == 'function' ? then : false;
};
var notify$1 = function (promise, state, isReject) {
var notify$1 = function (state, isReject) {
if (state.notified) return;
state.notified = true;
var chain = state.reactions;
@@ -6277,7 +6313,7 @@ var notify$1 = function (promise, state, isReject) {
try {
if (handler) {
if (!ok) {
if (state.rejection === UNHANDLED) onHandleUnhandled(promise, state);
if (state.rejection === UNHANDLED) onHandleUnhandled(state);
state.rejection = HANDLED;
}
if (handler === true) result = value;
@@ -6302,36 +6338,37 @@ var notify$1 = function (promise, state, isReject) {
}
state.reactions = [];
state.notified = false;
if (isReject && !state.rejection) onUnhandled(promise, state);
if (isReject && !state.rejection) onUnhandled(state);
});
};
var dispatchEvent = function (name, promise, reason) {
var event, handler;
if (DISPATCH_EVENT) {
event = document$2.createEvent('Event');
event = document$3.createEvent('Event');
event.promise = promise;
event.reason = reason;
event.initEvent(name, false, true);
global_1.dispatchEvent(event);
} else event = { promise: promise, reason: reason };
if (handler = global_1['on' + name]) handler(event);
if (!NATIVE_REJECTION_EVENT && (handler = global_1['on' + name])) handler(event);
else if (name === UNHANDLED_REJECTION) hostReportErrors('Unhandled promise rejection', reason);
};
var onUnhandled = function (promise, state) {
var onUnhandled = function (state) {
task$1.call(global_1, function () {
var promise = state.facade;
var value = state.value;
var IS_UNHANDLED = isUnhandled(state);
var result;
if (IS_UNHANDLED) {
result = perform(function () {
if (IS_NODE$1) {
if (engineIsNode) {
process$3.emit('unhandledRejection', value, promise);
} else dispatchEvent(UNHANDLED_REJECTION, promise, value);
});
// Browsers should not trigger `rejectionHandled` event if it was handled here, NodeJS - should
state.rejection = IS_NODE$1 || isUnhandled(state) ? UNHANDLED : HANDLED;
state.rejection = engineIsNode || isUnhandled(state) ? UNHANDLED : HANDLED;
if (result.error) throw result.value;
}
});
@@ -6341,55 +6378,56 @@ var isUnhandled = function (state) {
return state.rejection !== HANDLED && !state.parent;
};
var onHandleUnhandled = function (promise, state) {
var onHandleUnhandled = function (state) {
task$1.call(global_1, function () {
if (IS_NODE$1) {
var promise = state.facade;
if (engineIsNode) {
process$3.emit('rejectionHandled', promise);
} else dispatchEvent(REJECTION_HANDLED, promise, state.value);
});
};
var bind = function (fn, promise, state, unwrap) {
var bind = function (fn, state, unwrap) {
return function (value) {
fn(promise, state, value, unwrap);
fn(state, value, unwrap);
};
};
var internalReject = function (promise, state, value, unwrap) {
var internalReject = function (state, value, unwrap) {
if (state.done) return;
state.done = true;
if (unwrap) state = unwrap;
state.value = value;
state.state = REJECTED;
notify$1(promise, state, true);
notify$1(state, true);
};
var internalResolve = function (promise, state, value, unwrap) {
var internalResolve = function (state, value, unwrap) {
if (state.done) return;
state.done = true;
if (unwrap) state = unwrap;
try {
if (promise === value) throw TypeError$1("Promise can't be resolved itself");
if (state.facade === value) throw TypeError$1("Promise can't be resolved itself");
var then = isThenable(value);
if (then) {
microtask(function () {
var wrapper = { done: false };
try {
then.call(value,
bind(internalResolve, promise, wrapper, state),
bind(internalReject, promise, wrapper, state)
bind(internalResolve, wrapper, state),
bind(internalReject, wrapper, state)
);
} catch (error) {
internalReject(promise, wrapper, error, state);
internalReject(wrapper, error, state);
}
});
} else {
state.value = value;
state.state = FULFILLED;
notify$1(promise, state, false);
notify$1(state, false);
}
} catch (error) {
internalReject(promise, { done: false }, error, state);
internalReject({ done: false }, error, state);
}
};
@@ -6402,9 +6440,9 @@ if (FORCED$3) {
Internal.call(this);
var state = getInternalState$3(this);
try {
executor(bind(internalResolve, this, state), bind(internalReject, this, state));
executor(bind(internalResolve, state), bind(internalReject, state));
} catch (error) {
internalReject(this, state, error);
internalReject(state, error);
}
};
// eslint-disable-next-line no-unused-vars
@@ -6428,10 +6466,10 @@ if (FORCED$3) {
var reaction = newPromiseCapability$1(speciesConstructor(this, PromiseConstructor));
reaction.ok = typeof onFulfilled == 'function' ? onFulfilled : true;
reaction.fail = typeof onRejected == 'function' && onRejected;
reaction.domain = IS_NODE$1 ? process$3.domain : undefined;
reaction.domain = engineIsNode ? process$3.domain : undefined;
state.parent = true;
state.reactions.push(reaction);
if (state.state != PENDING) notify$1(this, state, false);
if (state.state != PENDING) notify$1(state, false);
return reaction.promise;
},
// `Promise.prototype.catch` method
@@ -6444,8 +6482,8 @@ if (FORCED$3) {
var promise = new Internal();
var state = getInternalState$3(promise);
this.promise = promise;
this.resolve = bind(internalResolve, promise, state);
this.reject = bind(internalReject, promise, state);
this.resolve = bind(internalResolve, state);
this.reject = bind(internalReject, state);
};
newPromiseCapability.f = newPromiseCapability$1 = function (C) {
return C === PromiseConstructor || C === PromiseWrapper
@@ -6516,7 +6554,7 @@ _export({ target: PROMISE, stat: true, forced: INCORRECT_ITERATION$1 }, {
var values = [];
var counter = 0;
var remaining = 1;
iterate_1(iterable, function (promise) {
iterate(iterable, function (promise) {
var index = counter++;
var alreadyCalled = false;
values.push(undefined);
@@ -6541,7 +6579,7 @@ _export({ target: PROMISE, stat: true, forced: INCORRECT_ITERATION$1 }, {
var reject = capability.reject;
var result = perform(function () {
var $promiseResolve = aFunction$1(C.resolve);
iterate_1(iterable, function (promise) {
iterate(iterable, function (promise) {
$promiseResolve.call(C, promise).then(capability.resolve, reject);
});
});
@@ -6788,12 +6826,17 @@ var $reduce = arrayReduce.left;
var STRICT_METHOD$5 = arrayMethodIsStrict('reduce');
var USES_TO_LENGTH$9 = arrayMethodUsesToLength('reduce', { 1: 0 });
// Chrome 80-82 has a critical bug
// https://bugs.chromium.org/p/chromium/issues/detail?id=1049982
var CHROME_BUG = !engineIsNode && engineV8Version > 79 && engineV8Version < 83;
// `Array.prototype.reduce` method
// https://tc39.github.io/ecma262/#sec-array.prototype.reduce
_export({ target: 'Array', proto: true, forced: !STRICT_METHOD$5 || !USES_TO_LENGTH$9 }, {
_export({ target: 'Array', proto: true, forced: !STRICT_METHOD$5 || !USES_TO_LENGTH$9 || CHROME_BUG }, {
reduce: function reduce(callbackfn /* , initialValue */) {
return $reduce(this, callbackfn, arguments.length, arguments.length > 1 ? arguments[1] : undefined);
}
@@ -7427,7 +7470,12 @@ function setAspectRatio(input) {
if (this.isVimeo && !this.config.vimeo.premium && this.supported.ui) {
var height = 100 / this.media.offsetWidth * parseInt(window.getComputedStyle(this.media).paddingBottom, 10);
var offset = (height - padding) / (height / 50);
this.media.style.transform = "translateY(-".concat(offset, "%)");
if (this.fullscreen.active) {
wrapper.style.paddingBottom = null;
} else {
this.media.style.transform = "translateY(-".concat(offset, "%)");
}
} else if (this.isHTML5) {
wrapper.classList.toggle(this.config.classNames.videoFixedRatio, ratio !== null);
}
@@ -9969,7 +10017,7 @@ var defaults$1 = {
// Sprite (for icons)
loadSprite: true,
iconPrefix: 'plyr',
iconUrl: 'https://cdn.plyr.io/3.6.2/plyr.svg',
iconUrl: 'https://cdn.plyr.io/3.6.3/plyr.svg',
// Blank video (used to prevent errors on source change)
blankVideo: 'https://cdn.plyr.io/static/blank.mp4',
// Quality default
@@ -10087,7 +10135,7 @@ var defaults$1 = {
vimeo: {
sdk: 'https://player.vimeo.com/api/player.js',
iframe: 'https://player.vimeo.com/video/{0}?{1}',
api: 'https://vimeo.com/api/v2/video/{0}.json'
api: 'https://vimeo.com/api/oembed.json?url={0}'
},
youtube: {
sdk: 'https://www.youtube.com/iframe_api',
@@ -10257,24 +10305,27 @@ var defaults$1 = {
title: false,
speed: true,
transparent: false,
// Custom settings from Plyr
customControls: true,
referrerPolicy: null,
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/referrerPolicy
// Whether the owner of the video has a Pro or Business account
// (which allows us to properly hide controls without CSS hacks, etc)
premium: false,
// Custom settings from Plyr
referrerPolicy: null // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/referrerPolicy
premium: false
},
// YouTube plugin
youtube: {
noCookie: true,
// Whether to use an alternative version of YouTube without cookies
rel: 0,
// No related vids
showinfo: 0,
// Hide info
iv_load_policy: 3,
// Hide annotations
modestbranding: 1 // Hide logos as much as possible (they still show one in the corner when paused)
modestbranding: 1,
// Hide logos as much as possible (they still show one in the corner when paused)
// Custom settings from Plyr
customControls: true,
noCookie: false // Whether to use an alternative version of YouTube without cookies
}
};
@@ -10393,7 +10444,7 @@ var Fullscreen = /*#__PURE__*/function () {
return;
}
_this.toggle();
_this.player.listeners.proxy(event, _this.toggle, 'fullscreen');
}); // Tap focus when in fullscreen
on.call(this, this.player.elements.container, 'keydown', function (event) {
@@ -10416,10 +10467,12 @@ var Fullscreen = /*#__PURE__*/function () {
if (is$1.element(button)) {
button.pressed = this.active;
} // Trigger an event
} // Always trigger events on the plyr / media element (not a fullscreen container) and let them bubble up
triggerEvent.call(this.player, this.target, this.active ? 'enterfullscreen' : 'exitfullscreen', true);
var target = this.target === this.player.media ? this.target : this.player.elements.container; // Trigger an event
triggerEvent.call(this.player, target, this.active ? 'enterfullscreen' : 'exitfullscreen', true);
}
}, {
key: "toggleFallback",
@@ -10814,7 +10867,9 @@ var ui = {
} // Set property synchronously to respect the call order
this.media.setAttribute('data-poster', poster); // Wait until ui is ready
this.media.setAttribute('data-poster', poster); // Show the poster
this.elements.poster.removeAttribute('hidden'); // Wait until ui is ready
return ready.call(this) // Load image
.then(function () {
@@ -10898,7 +10953,7 @@ var ui = {
// Loop through values (as they are the keys when the object is spread 🤔)
Object.values(_objectSpread2({}, this.media.style)) // We're only fussed about Plyr specific properties
.filter(function (key) {
return !is$1.empty(key) && key.startsWith('--plyr');
return !is$1.empty(key) && is$1.string(key) && key.startsWith('--plyr');
}).forEach(function (key) {
// Set on the container
_this5.elements.container.style.setProperty(key, _this5.media.style.getPropertyValue(key)); // Clean up from media element
@@ -11246,7 +11301,14 @@ var Listeners = /*#__PURE__*/function () {
ratio = _setPlayerSize.ratio; // Set Vimeo gutter
setGutter(ratio, padding, isEnter); // If not using native browser fullscreen API, we need to check for resizes of viewport
setGutter(ratio, padding, isEnter); // Horrible hack for Safari 14 not repainting properly on entering fullscreen
if (isEnter) {
setTimeout(function () {
return repaint(elements.container);
}, 100);
} // If not using native browser fullscreen API, we need to check for resizes of viewport
if (!usingNative) {
if (isEnter) {
@@ -11437,9 +11499,17 @@ var Listeners = /*#__PURE__*/function () {
this.bind(elements.buttons.restart, 'click', player.restart, 'restart'); // Rewind
this.bind(elements.buttons.rewind, 'click', player.rewind, 'rewind'); // Rewind
this.bind(elements.buttons.rewind, 'click', function () {
// Record seek time so we can prevent hiding controls for a few seconds after rewind
player.lastSeekTime = Date.now();
player.rewind();
}, 'rewind'); // Rewind
this.bind(elements.buttons.fastForward, 'click', player.forward, 'fastForward'); // Mute toggle
this.bind(elements.buttons.fastForward, 'click', function () {
// Record seek time so we can prevent hiding controls for a few seconds after fast forward
player.lastSeekTime = Date.now();
player.forward();
}, 'fastForward'); // Mute toggle
this.bind(elements.buttons.mute, 'click', function () {
player.muted = !player.muted;
@@ -12147,35 +12217,32 @@ var vimeo = {
} // Inject the package
var poster = player.poster;
if (premium) {
iframe.setAttribute('data-poster', poster);
if (premium || !config.customControls) {
iframe.setAttribute('data-poster', player.poster);
player.media = replaceElement(iframe, player.media);
} else {
var wrapper = createElement('div', {
class: player.config.classNames.embedContainer,
'data-poster': poster
'data-poster': player.poster
});
wrapper.appendChild(iframe);
player.media = replaceElement(wrapper, player.media);
} // Get poster image
fetch(format(player.config.urls.vimeo.api, id), 'json').then(function (response) {
if (is$1.empty(response)) {
return;
} // Get the URL for thumbnail
if (!config.customControls) {
fetch(format(player.config.urls.vimeo.api, src)).then(function (response) {
if (is$1.empty(response) || !response.thumbnail_url) {
return;
} // Set and show poster
var url = new URL(response[0].thumbnail_large); // Get original image
url.pathname = "".concat(url.pathname.split('_')[0], ".jpg"); // Set and show poster
ui.setPoster.call(player, url.href).catch(function () {});
}); // Setup instance
ui.setPoster.call(player, response.thumbnail_url).catch(function () {});
});
} // Setup instance
// https://github.com/vimeo/player.js
player.embed = new window.Vimeo.Player(iframe, {
autopause: player.config.autopause,
muted: player.muted
@@ -12415,9 +12482,11 @@ var vimeo = {
triggerEvent.call(player, player.media, 'error');
}); // Rebuild UI
setTimeout(function () {
return ui.build.call(player);
}, 0);
if (config.customControls) {
setTimeout(function () {
return ui.build.call(player);
}, 0);
}
}
};
@@ -12508,7 +12577,8 @@ var youtube = {
},
// API ready
ready: function ready() {
var player = this; // Ignore already setup (race condition)
var player = this;
var config = player.config.youtube; // Ignore already setup (race condition)
var currentId = player.media && player.media.getAttribute('id');
@@ -12525,53 +12595,53 @@ var youtube = {
var videoId = parseId$1(source);
var id = generateId(player.provider); // Get poster, if already set
var poster = player.poster; // Replace media element
var id = generateId(player.provider); // Replace media element
var container = createElement('div', {
id: id,
'data-poster': poster
'data-poster': config.customControls ? player.poster : undefined
});
player.media = replaceElement(container, player.media); // Id to poster wrapper
player.media = replaceElement(container, player.media); // Only load the poster when using custom controls
var posterSrc = function posterSrc(s) {
return "https://i.ytimg.com/vi/".concat(videoId, "/").concat(s, "default.jpg");
}; // Check thumbnail images in order of quality, but reject fallback thumbnails (120px wide)
if (config.customControls) {
var posterSrc = function posterSrc(s) {
return "https://i.ytimg.com/vi/".concat(videoId, "/").concat(s, "default.jpg");
}; // Check thumbnail images in order of quality, but reject fallback thumbnails (120px wide)
loadImage(posterSrc('maxres'), 121) // Higest quality and unpadded
.catch(function () {
return loadImage(posterSrc('sd'), 121);
}) // 480p padded 4:3
.catch(function () {
return loadImage(posterSrc('hq'));
}) // 360p padded 4:3. Always exists
.then(function (image) {
return ui.setPoster.call(player, image.src);
}).then(function (src) {
// If the image is padded, use background-size "cover" instead (like youtube does too with their posters)
if (!src.includes('maxres')) {
player.elements.poster.style.backgroundSize = 'cover';
}
}).catch(function () {});
var config = player.config.youtube; // Setup instance
loadImage(posterSrc('maxres'), 121) // Higest quality and unpadded
.catch(function () {
return loadImage(posterSrc('sd'), 121);
}) // 480p padded 4:3
.catch(function () {
return loadImage(posterSrc('hq'));
}) // 360p padded 4:3. Always exists
.then(function (image) {
return ui.setPoster.call(player, image.src);
}).then(function (src) {
// If the image is padded, use background-size "cover" instead (like youtube does too with their posters)
if (!src.includes('maxres')) {
player.elements.poster.style.backgroundSize = 'cover';
}
}).catch(function () {});
} // Setup instance
// https://developers.google.com/youtube/iframe_api_reference
player.embed = new window.YT.Player(id, {
player.embed = new window.YT.Player(player.media, {
videoId: videoId,
host: getHost$1(config),
playerVars: extend({}, {
autoplay: player.config.autoplay ? 1 : 0,
// Autoplay
hl: player.config.hl,
autoplay: player.config.autoplay ? 1 : 0,
// iframe interface language
controls: player.supported.ui ? 0 : 1,
// Only show controls if not fully supported
disablekb: 1,
hl: player.config.hl,
// Only show controls if not fully supported or opted out
controls: player.supported.ui && config.customControls ? 0 : 1,
// Disable keyboard as we handle it
playsinline: !player.config.fullscreen.iosNative ? 1 : 0,
disablekb: 1,
// Allow iOS inline playback
playsinline: !player.config.fullscreen.iosNative ? 1 : 0,
// Captions are flaky on YouTube
cc_load_policy: player.captions.active ? 1 : 0,
cc_lang_pref: player.config.captions.language,
@@ -12682,6 +12752,7 @@ var youtube = {
var toggle = is$1.boolean(input) ? input : muted;
muted = toggle;
instance[toggle ? 'mute' : 'unMute']();
instance.setVolume(volume * 100);
triggerEvent.call(player, player.media, 'volumechange');
}
}); // Source
@@ -12704,7 +12775,7 @@ var youtube = {
return player.config.speed.options.includes(s);
}); // Set the tabindex to avoid focus entering iframe
if (player.supported.ui) {
if (player.supported.ui && config.customControls) {
player.media.setAttribute('tabindex', -1);
}
@@ -12731,9 +12802,11 @@ var youtube = {
}
}, 200); // Rebuild UI
setTimeout(function () {
return ui.build.call(player);
}, 50);
if (config.customControls) {
setTimeout(function () {
return ui.build.call(player);
}, 50);
}
},
onStateChange: function onStateChange(event) {
// Get the instance
@@ -12779,7 +12852,7 @@ var youtube = {
case 1:
// Restore paused state (YouTube starts playing on seek if the video hasn't been played yet)
if (!player.config.autoplay && player.media.paused && !player.embed.hasPlayed) {
if (config.customControls && !player.config.autoplay && player.media.paused && !player.embed.hasPlayed) {
player.media.pause();
} else {
assurePlaybackState$1.call(player, true);
@@ -12852,7 +12925,8 @@ var media = {
wrap$1(this.media, this.elements.wrapper); // Poster image container
this.elements.poster = createElement('div', {
class: this.config.classNames.poster
class: this.config.classNames.poster,
hidden: ''
});
this.elements.wrapper.appendChild(this.elements.poster);
}
@@ -14720,9 +14794,9 @@ var Plyr = /*#__PURE__*/function () {
if (this.isHTML5 && this.config.autoplay) {
setTimeout(function () {
this.once('canplay', function () {
return silencePromise(_this.play());
}, 10);
});
} // Seek time will be recorded (in listeners.js) so we can prevent hiding controls for a few seconds after seek
@@ -15011,7 +15085,9 @@ var Plyr = /*#__PURE__*/function () {
}
} else {
// Unbind listeners
unbindListeners.call(_this3); // Replace the container with the original element provided
unbindListeners.call(_this3); // Cancel current network requests
html5.cancelRequests.call(_this3); // Replace the container with the original element provided
replaceElement(_this3.elements.original, _this3.elements.container); // Event
+30 -30
View File
@@ -1,6 +1,6 @@
{
"name": "plyr",
"version": "3.6.2",
"version": "3.6.3",
"description": "A simple, accessible and customizable HTML5, YouTube and Vimeo media player",
"homepage": "https://plyr.io",
"author": "Sam Potts <sam@potts.es>",
@@ -35,66 +35,66 @@
"lint:fix": "eslint --fix src/js",
"remark": "remark -f --use 'validate-links=repository:\"sampotts/plyr\"' '{,!(node_modules),.?**/}*.md'",
"deploy": "yarn lint && gulp version && gulp build && gulp deploy",
"format": "prettier --write \"./{src,demo/src}/**/*.{js,scss}\""
"format": "prettier --write \"./{src,demo/src}/**/*.{js,scss}\"",
"start": "gulp"
},
"devDependencies": {
"@sampotts/eslint-config": "1.1.5",
"ansi-colors": "^4.1.1",
"autoprefixer": "^9.7.6",
"aws-sdk": "^2.668.0",
"@babel/core": "^7.9.6",
"@babel/preset-env": "^7.9.6",
"autoprefixer": "^10.0.2",
"aws-sdk": "^2.773.0",
"@babel/core": "^7.12.3",
"@babel/preset-env": "^7.12.1",
"babel-eslint": "^10.1.0",
"browser-sync": "^2.26.7",
"del": "^5.1.0",
"eslint": "^6.8.0",
"eslint-config-airbnb-base": "^14.1.0",
"eslint-config-prettier": "^6.11.0",
"eslint-plugin-import": "^2.20.2",
"eslint-plugin-simple-import-sort": "^5.0.3",
"browser-sync": "^2.26.13",
"del": "^6.0.0",
"eslint": "^7.3.1",
"fancy-log": "^1.3.3",
"fastly-purge": "^1.0.1",
"git-branch": "^2.0.1",
"gulp": "^4.0.2",
"gulp-awspublish": "^4.1.1",
"gulp-awspublish": "^4.1.2",
"gulp-better-rollup": "^4.0.1",
"gulp-filter": "^6.0.0",
"gulp-header": "^2.0.9",
"gulp-hub": "^4.2.0",
"gulp-if": "^3.0.0",
"gulp-imagemin": "^7.1.0",
"gulp-open": "^3.0.1",
"gulp-plumber": "^1.2.1",
"gulp-postcss": "^8.0.0",
"gulp-postcss": "^9.0.0",
"gulp-rename": "^2.0.0",
"gulp-replace": "^1.0.0",
"gulp-sass": "^4.1.0",
"gulp-size": "^3.0.0",
"gulp-sourcemaps": "^2.6.5",
"gulp-sourcemaps": "^3.0.0",
"gulp-svgstore": "^7.0.1",
"gulp-terser": "^1.2.0",
"gulp-terser": "^1.4.1",
"postcss": "^8.1.7",
"postcss-clean": "^1.1.0",
"postcss-custom-properties": "^9.1.1",
"prettier-eslint": "^9.0.1",
"postcss-custom-properties": "^10.0.0",
"prettier-eslint": "^11.0.0",
"prettier-stylelint": "^0.4.2",
"remark-cli": "^8.0.0",
"remark-validate-links": "^10.0.0",
"rollup": "^2.7.6",
"remark-cli": "^9.0.0",
"remark-validate-links": "^10.0.2",
"rollup": "^2.33.1",
"rollup-plugin-babel": "^4.4.0",
"rollup-plugin-commonjs": "^10.1.0",
"rollup-plugin-node-resolve": "^5.2.0",
"stylelint": "^13.3.3",
"stylelint-config-prettier": "^8.0.1",
"stylelint": "^13.7.2",
"stylelint-config-prettier": "^8.0.2",
"stylelint-config-recommended": "^3.0.0",
"stylelint-config-sass-guidelines": "^7.0.0",
"stylelint-order": "^4.0.0",
"stylelint-scss": "^3.17.1",
"stylelint-config-sass-guidelines": "^7.1.0",
"stylelint-order": "^4.1.0",
"stylelint-scss": "^3.18.0",
"stylelint-selector-bem-pattern": "^2.1.0",
"through2": "^3.0.1"
"through2": "^4.0.2"
},
"dependencies": {
"core-js": "^3.6.5",
"core-js": "^3.7.0",
"custom-event-polyfill": "^1.0.7",
"loadjs": "^4.2.0",
"rangetouch": "^2.0.1",
"url-polyfill": "^1.1.8"
"url-polyfill": "^1.1.12"
}
}
+13 -13
View File
@@ -56,7 +56,7 @@ const captions = {
if (browser.isIE && window.URL) {
const elements = this.media.querySelectorAll('track');
Array.from(elements).forEach(track => {
Array.from(elements).forEach((track) => {
const src = track.getAttribute('src');
const url = parseUrl(src);
@@ -66,7 +66,7 @@ const captions = {
['http:', 'https:'].includes(url.protocol)
) {
fetch(src, 'blob')
.then(blob => {
.then((blob) => {
track.setAttribute('src', window.URL.createObjectURL(blob));
})
.catch(() => {
@@ -84,7 +84,7 @@ const captions = {
// * toggled: The real captions state
const browserLanguages = navigator.languages || [navigator.language || navigator.userLanguage || 'en'];
const languages = dedupe(browserLanguages.map(language => language.split('-')[0]));
const languages = dedupe(browserLanguages.map((language) => language.split('-')[0]));
let language = (this.storage.get('language') || this.config.captions.language || 'auto').toLowerCase();
// Use first browser language when language is 'auto'
@@ -119,13 +119,13 @@ const captions = {
const tracks = captions.getTracks.call(this, true);
// Get the wanted language
const { active, language, meta, currentTrackNode } = this.captions;
const languageExists = Boolean(tracks.find(track => track.language === language));
const languageExists = Boolean(tracks.find((track) => track.language === language));
// Handle tracks (add event listener and "pseudo"-default)
if (this.isHTML5 && this.isVideo) {
tracks
.filter(track => !meta.get(track))
.forEach(track => {
.filter((track) => !meta.get(track))
.forEach((track) => {
this.debug.log('Track added', track);
// Attempt to store if the original dom element was "default"
@@ -309,19 +309,19 @@ const captions = {
// For HTML5, use cache instead of current tracks when it exists (if captions.update is false)
// Filter out removed tracks and tracks that aren't captions/subtitles (for example metadata)
return tracks
.filter(track => !this.isHTML5 || update || this.captions.meta.has(track))
.filter(track => ['captions', 'subtitles'].includes(track.kind));
.filter((track) => !this.isHTML5 || update || this.captions.meta.has(track))
.filter((track) => ['captions', 'subtitles'].includes(track.kind));
},
// Match tracks based on languages and get the first
findTrack(languages, force = false) {
const tracks = captions.getTracks.call(this);
const sortIsDefault = track => Number((this.captions.meta.get(track) || {}).default);
const sortIsDefault = (track) => Number((this.captions.meta.get(track) || {}).default);
const sorted = Array.from(tracks).sort((a, b) => sortIsDefault(b) - sortIsDefault(a));
let track;
languages.every(language => {
track = sorted.find(t => t.language === language);
languages.every((language) => {
track = sorted.find((t) => t.language === language);
return !track; // Break iteration if there is a match
});
@@ -383,12 +383,12 @@ const captions = {
const track = captions.getCurrentTrack.call(this);
cues = Array.from((track || {}).activeCues || [])
.map(cue => cue.getCueAsHTML())
.map((cue) => cue.getCueAsHTML())
.map(getHTML);
}
// Set new caption text
const content = cues.map(cueText => cueText.trim()).join('\n');
const content = cues.map((cueText) => cueText.trim()).join('\n');
const changed = content !== this.elements.captions.innerHTML;
if (changed) {
+8 -5
View File
@@ -61,7 +61,7 @@ const defaults = {
// Sprite (for icons)
loadSprite: true,
iconPrefix: 'plyr',
iconUrl: 'https://cdn.plyr.io/3.6.2/plyr.svg',
iconUrl: 'https://cdn.plyr.io/3.6.3/plyr.svg',
// Blank video (used to prevent errors on source change)
blankVideo: 'https://cdn.plyr.io/static/blank.mp4',
@@ -200,7 +200,7 @@ const defaults = {
vimeo: {
sdk: 'https://player.vimeo.com/api/player.js',
iframe: 'https://player.vimeo.com/video/{0}?{1}',
api: 'https://vimeo.com/api/v2/video/{0}.json',
api: 'https://vimeo.com/api/oembed.json?url={0}',
},
youtube: {
sdk: 'https://www.youtube.com/iframe_api',
@@ -422,20 +422,23 @@ const defaults = {
title: false,
speed: true,
transparent: false,
// Custom settings from Plyr
customControls: true,
referrerPolicy: null, // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/referrerPolicy
// Whether the owner of the video has a Pro or Business account
// (which allows us to properly hide controls without CSS hacks, etc)
premium: false,
// Custom settings from Plyr
referrerPolicy: null, // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/referrerPolicy
},
// YouTube plugin
youtube: {
noCookie: true, // Whether to use an alternative version of YouTube without cookies
rel: 0, // No related vids
showinfo: 0, // Hide info
iv_load_policy: 3, // Hide annotations
modestbranding: 1, // Hide logos as much as possible (they still show one in the corner when paused)
// Custom settings from Plyr
customControls: true,
noCookie: false, // Whether to use an alternative version of YouTube without cookies
},
};
+25 -27
View File
@@ -179,7 +179,7 @@ const controls = {
iconPressed: null,
};
['element', 'icon', 'label'].forEach(key => {
['element', 'icon', 'label'].forEach((key) => {
if (Object.keys(attributes).includes(key)) {
props[key] = attributes[key];
delete attributes[key];
@@ -193,7 +193,7 @@ const controls = {
// Set class name
if (Object.keys(attributes).includes('class')) {
if (!attributes.class.split(' ').some(c => c === this.config.classNames.control)) {
if (!attributes.class.split(' ').some((c) => c === this.config.classNames.control)) {
extend(attributes, {
class: `${attributes.class} ${this.config.classNames.control}`,
});
@@ -401,7 +401,7 @@ const controls = {
this,
menuItem,
'keydown keyup',
event => {
(event) => {
// We only care about space and ⬆️ ⬇️ ➡️
if (![32, 38, 39, 40].includes(event.which)) {
return;
@@ -448,7 +448,7 @@ const controls = {
// Enter will fire a `click` event but we still need to manage focus
// So we bind to keyup which fires after and set focus here
on.call(this, menuItem, 'keyup', event => {
on.call(this, menuItem, 'keyup', (event) => {
if (event.which !== 13) {
return;
}
@@ -493,8 +493,8 @@ const controls = {
// Ensure exclusivity
if (check) {
Array.from(menuItem.parentNode.children)
.filter(node => matches(node, '[role="menuitemradio"]'))
.forEach(node => node.setAttribute('aria-checked', 'false'));
.filter((node) => matches(node, '[role="menuitemradio"]'))
.forEach((node) => node.setAttribute('aria-checked', 'false'));
}
menuItem.setAttribute('aria-checked', check ? 'true' : 'false');
@@ -504,7 +504,7 @@ const controls = {
this.listeners.bind(
menuItem,
'click keyup',
event => {
(event) => {
if (is.keyboardEvent(event) && event.which !== 32) {
return;
}
@@ -698,7 +698,7 @@ const controls = {
}
const visible = `${this.config.classNames.tooltip}--visible`;
const toggle = show => toggleClass(this.elements.display.seekTooltip, visible, show);
const toggle = (show) => toggleClass(this.elements.display.seekTooltip, visible, show);
// Hide on touch
if (this.touch) {
@@ -894,7 +894,7 @@ const controls = {
// Set options if passed and filter based on uniqueness and config
if (is.array(options)) {
this.options.quality = dedupe(options).filter(quality => this.config.quality.options.includes(quality));
this.options.quality = dedupe(options).filter((quality) => this.config.quality.options.includes(quality));
}
// Toggle the pane and tab
@@ -913,7 +913,7 @@ const controls = {
}
// Get the badge HTML for HD, 4K etc
const getBadge = quality => {
const getBadge = (quality) => {
const label = i18n.get(`qualityBadge.${quality}`, this.config);
if (!label.length) {
@@ -929,7 +929,7 @@ const controls = {
const sorting = this.config.quality.options;
return sorting.indexOf(a) > sorting.indexOf(b) ? 1 : -1;
})
.forEach(quality => {
.forEach((quality) => {
controls.createMenuItem.call(this, {
value: quality,
list,
@@ -1052,7 +1052,7 @@ const controls = {
const list = this.elements.settings.panels.speed.querySelector('[role="menu"]');
// Filter out invalid speeds
this.options.speed = this.options.speed.filter(o => o >= this.minimumSpeed && o <= this.maximumSpeed);
this.options.speed = this.options.speed.filter((o) => o >= this.minimumSpeed && o <= this.maximumSpeed);
// Toggle the pane and tab
const toggle = !is.empty(this.options.speed) && this.options.speed.length > 1;
@@ -1070,7 +1070,7 @@ const controls = {
}
// Create items
this.options.speed.forEach(speed => {
this.options.speed.forEach((speed) => {
controls.createMenuItem.call(this, {
value: speed,
list,
@@ -1085,7 +1085,7 @@ const controls = {
// Check if we need to hide/show the settings menu
checkMenu() {
const { buttons } = this.elements.settings;
const visible = !is.empty(buttons) && Object.values(buttons).some(button => !button.hidden);
const visible = !is.empty(buttons) && Object.values(buttons).some((button) => !button.hidden);
toggleHidden(this.elements.settings.menu, !visible);
},
@@ -1099,7 +1099,7 @@ const controls = {
let target = pane;
if (!is.element(target)) {
target = Object.values(this.elements.settings.panels).find(p => !p.hidden);
target = Object.values(this.elements.settings.panels).find((p) => !p.hidden);
}
const firstItem = target.querySelector('[role^="menuitem"]');
@@ -1191,7 +1191,7 @@ const controls = {
// Hide all other panels
const container = target.parentNode;
const current = Array.from(container.children).find(node => !node.hidden);
const current = Array.from(container.children).find((node) => !node.hidden);
// If we can do fancy animations, we'll animate the height/width
if (support.transitions && !support.reducedMotion) {
@@ -1203,7 +1203,7 @@ const controls = {
const size = controls.getMenuSize.call(this, target);
// Restore auto height/width
const restore = event => {
const restore = (event) => {
// We're only bothered about height and width on the container
if (event.target !== container || !['width', 'height'].includes(event.propertyName)) {
return;
@@ -1275,7 +1275,7 @@ const controls = {
const defaultAttributes = { class: 'plyr__controls__item' };
// Loop through controls in order
dedupe(is.array(this.config.controls) ? this.config.controls: []).forEach(control => {
dedupe(is.array(this.config.controls) ? this.config.controls : []).forEach((control) => {
// Restart button
if (control === 'restart') {
container.appendChild(createButton.call(this, 'restart', defaultAttributes));
@@ -1437,7 +1437,7 @@ const controls = {
this.elements.settings.panels.home = home;
// Build the menu items
this.config.settings.forEach(type => {
this.config.settings.forEach((type) => {
// TODO: bundle this with the createMenuItem helper and bindings
const menuItem = createElement(
'button',
@@ -1510,7 +1510,7 @@ const controls = {
this,
pane,
'keydown',
event => {
(event) => {
// We only care about <-
if (event.which !== 37) {
return;
@@ -1661,7 +1661,7 @@ const controls = {
}
// Replace props with their value
const replace = input => {
const replace = (input) => {
let result = input;
Object.entries(props).forEach(([key, value]) => {
@@ -1702,7 +1702,7 @@ const controls = {
// Add pressed property to buttons
if (!is.empty(this.elements.buttons)) {
const addProperty = button => {
const addProperty = (button) => {
const className = this.config.classNames.controlPressed;
Object.defineProperty(button, 'pressed', {
enumerable: true,
@@ -1718,11 +1718,9 @@ const controls = {
// Toggle classname when pressed property is set
Object.values(this.elements.buttons)
.filter(Boolean)
.forEach(button => {
.forEach((button) => {
if (is.array(button) || is.nodeList(button)) {
Array.from(button)
.filter(Boolean)
.forEach(addProperty);
Array.from(button).filter(Boolean).forEach(addProperty);
} else {
addProperty(button);
}
@@ -1740,7 +1738,7 @@ const controls = {
const selector = `${selectors.controls.wrapper} ${selectors.labels} .${classNames.hidden}`;
const labels = getElements.call(this, selector);
Array.from(labels).forEach(label => {
Array.from(labels).forEach((label) => {
toggleClass(label, this.config.classNames.hidden, false);
toggleClass(label, this.config.classNames.tooltip, true);
});
+9 -7
View File
@@ -5,7 +5,7 @@
// ==========================================================================
import browser from './utils/browser';
import { closest,getElements, hasClass, toggleClass } from './utils/elements';
import { closest, getElements, hasClass, toggleClass } from './utils/elements';
import { on, triggerEvent } from './utils/events';
import is from './utils/is';
import { silencePromise } from './utils/promise';
@@ -43,17 +43,17 @@ class Fullscreen {
);
// Fullscreen toggle on double click
on.call(this.player, this.player.elements.container, 'dblclick', event => {
on.call(this.player, this.player.elements.container, 'dblclick', (event) => {
// Ignore double click in controls
if (is.element(this.player.elements.controls) && this.player.elements.controls.contains(event.target)) {
return;
}
this.toggle();
this.player.listeners.proxy(event, this.toggle, 'fullscreen');
});
// Tap focus when in fullscreen
on.call(this, this.player.elements.container, 'keydown', event => this.trapFocus(event));
on.call(this, this.player.elements.container, 'keydown', (event) => this.trapFocus(event));
// Update the UI
this.update();
@@ -85,7 +85,7 @@ class Fullscreen {
let value = '';
const prefixes = ['webkit', 'moz', 'ms'];
prefixes.some(pre => {
prefixes.some((pre) => {
if (is.function(document[`${pre}ExitFullscreen`]) || is.function(document[`${pre}CancelFullScreen`])) {
value = pre;
return true;
@@ -145,8 +145,10 @@ class Fullscreen {
button.pressed = this.active;
}
// Always trigger events on the plyr / media element (not a fullscreen container) and let them bubble up
const target = this.target === this.player.media ? this.target : this.player.elements.container;
// Trigger an event
triggerEvent.call(this.player, this.target, this.active ? 'enterfullscreen' : 'exitfullscreen', true);
triggerEvent.call(this.player, target, this.active ? 'enterfullscreen' : 'exitfullscreen', true);
}
toggleFallback(toggle = false) {
@@ -189,7 +191,7 @@ class Fullscreen {
} else if (this.cleanupViewport) {
viewport.content = viewport.content
.split(',')
.filter(part => part.trim() !== property)
.filter((part) => part.trim() !== property)
.join(',');
}
}
+4 -4
View File
@@ -18,7 +18,7 @@ const html5 = {
const sources = Array.from(this.media.querySelectorAll('source'));
// Filter out unsupported sources (if type is specified)
return sources.filter(source => {
return sources.filter((source) => {
const type = source.getAttribute('type');
if (is.empty(type)) {
@@ -39,7 +39,7 @@ const html5 = {
// Get sizes from <source> elements
return html5.getSources
.call(this)
.map(source => Number(source.getAttribute('size')))
.map((source) => Number(source.getAttribute('size')))
.filter(Boolean);
},
@@ -63,7 +63,7 @@ const html5 = {
get() {
// Get sources
const sources = html5.getSources.call(player);
const source = sources.find(s => s.getAttribute('src') === player.source);
const source = sources.find((s) => s.getAttribute('src') === player.source);
// Return size, if match is found
return source && Number(source.getAttribute('size'));
@@ -80,7 +80,7 @@ const html5 = {
// Get sources
const sources = html5.getSources.call(player);
// Get first match for requested size
const source = sources.find(s => Number(s.getAttribute('size')) === input);
const source = sources.find((s) => Number(s.getAttribute('size')) === input);
// No matching source found
if (!source) {
+61 -38
View File
@@ -277,7 +277,7 @@ class Listeners {
player,
elements.container,
'mousemove mouseleave touchstart touchmove enterfullscreen exitfullscreen',
event => {
(event) => {
const { controls: controlsElement } = elements;
// Remove button states for fullscreen
@@ -319,7 +319,7 @@ class Listeners {
};
// Resize on fullscreen change
const setPlayerSize = measure => {
const setPlayerSize = (measure) => {
// If we don't need to measure the viewport
if (!measure) {
return setAspectRatio.call(player);
@@ -336,7 +336,7 @@ class Listeners {
timers.resized = setTimeout(setPlayerSize, 50);
};
on.call(player, elements.container, 'enterfullscreen exitfullscreen', event => {
on.call(player, elements.container, 'enterfullscreen exitfullscreen', (event) => {
const { target, usingNative } = player.fullscreen;
// Ignore events not from target
@@ -356,6 +356,11 @@ class Listeners {
// Set Vimeo gutter
setGutter(ratio, padding, isEnter);
// Horrible hack for Safari 14 not repainting properly on entering fullscreen
if (isEnter) {
setTimeout(() => repaint(elements.container), 100);
}
// If not using native browser fullscreen API, we need to check for resizes of viewport
if (!usingNative) {
if (isEnter) {
@@ -373,10 +378,10 @@ class Listeners {
const { elements } = player;
// Time change on media
on.call(player, player.media, 'timeupdate seeking seeked', event => controls.timeUpdate.call(player, event));
on.call(player, player.media, 'timeupdate seeking seeked', (event) => controls.timeUpdate.call(player, event));
// Display duration
on.call(player, player.media, 'durationchange loadeddata loadedmetadata', event =>
on.call(player, player.media, 'durationchange loadeddata loadedmetadata', (event) =>
controls.durationUpdate.call(player, event),
);
@@ -393,20 +398,20 @@ class Listeners {
});
// Check for buffer progress
on.call(player, player.media, 'progress playing seeking seeked', event =>
on.call(player, player.media, 'progress playing seeking seeked', (event) =>
controls.updateProgress.call(player, event),
);
// Handle volume changes
on.call(player, player.media, 'volumechange', event => controls.updateVolume.call(player, event));
on.call(player, player.media, 'volumechange', (event) => controls.updateVolume.call(player, event));
// Handle play/pause
on.call(player, player.media, 'playing play pause ended emptied timeupdate', event =>
on.call(player, player.media, 'playing play pause ended emptied timeupdate', (event) =>
ui.checkPlaying.call(player, event),
);
// Loading state
on.call(player, player.media, 'waiting canplay seeked playing', event => ui.checkLoading.call(player, event));
on.call(player, player.media, 'waiting canplay seeked playing', (event) => ui.checkLoading.call(player, event));
// Click video
if (player.supported.ui && player.config.clickToPlay && !player.isAudio) {
@@ -419,7 +424,7 @@ class Listeners {
}
// On click play, pause or restart
on.call(player, elements.container, 'click', event => {
on.call(player, elements.container, 'click', (event) => {
const targets = [elements.container, wrapper];
// Ignore if click if not container or in video wrapper
@@ -459,7 +464,7 @@ class Listeners {
player,
elements.wrapper,
'contextmenu',
event => {
(event) => {
event.preventDefault();
},
false,
@@ -485,7 +490,7 @@ class Listeners {
});
// Quality change
on.call(player, player.media, 'qualitychange', event => {
on.call(player, player.media, 'qualitychange', (event) => {
// Update UI
controls.updateSetting.call(player, 'quality', null, event.detail.quality);
});
@@ -499,7 +504,7 @@ class Listeners {
// Bubble up key events for Edge
const proxyEvents = player.config.events.concat(['keyup', 'keydown']).join(' ');
on.call(player, player.media, proxyEvents, event => {
on.call(player, player.media, proxyEvents, (event) => {
let { detail = {} } = event;
// Get error details from media
@@ -539,7 +544,7 @@ class Listeners {
player,
element,
type,
event => this.proxy(event, defaultHandler, customHandlerKey),
(event) => this.proxy(event, defaultHandler, customHandlerKey),
passive && !hasCustomHandler,
);
}
@@ -553,7 +558,7 @@ class Listeners {
// Play/pause toggle
if (elements.buttons.play) {
Array.from(elements.buttons.play).forEach(button => {
Array.from(elements.buttons.play).forEach((button) => {
this.bind(
button,
'click',
@@ -569,10 +574,28 @@ class Listeners {
this.bind(elements.buttons.restart, 'click', player.restart, 'restart');
// Rewind
this.bind(elements.buttons.rewind, 'click', player.rewind, 'rewind');
this.bind(
elements.buttons.rewind,
'click',
() => {
// Record seek time so we can prevent hiding controls for a few seconds after rewind
player.lastSeekTime = Date.now();
player.rewind();
},
'rewind',
);
// Rewind
this.bind(elements.buttons.fastForward, 'click', player.forward, 'fastForward');
this.bind(
elements.buttons.fastForward,
'click',
() => {
// Record seek time so we can prevent hiding controls for a few seconds after fast forward
player.lastSeekTime = Date.now();
player.forward();
},
'fastForward',
);
// Mute toggle
this.bind(
@@ -624,7 +647,7 @@ class Listeners {
this.bind(
elements.buttons.settings,
'click',
event => {
(event) => {
// Prevent the document click listener closing the menu
event.stopPropagation();
event.preventDefault();
@@ -641,7 +664,7 @@ class Listeners {
this.bind(
elements.buttons.settings,
'keyup',
event => {
(event) => {
const code = event.which;
// We only care about space and return
@@ -669,21 +692,21 @@ class Listeners {
);
// Escape closes menu
this.bind(elements.settings.menu, 'keydown', event => {
this.bind(elements.settings.menu, 'keydown', (event) => {
if (event.which === 27) {
controls.toggleMenu.call(player, event);
}
});
// Set range input alternative "value", which matches the tooltip time (#954)
this.bind(elements.inputs.seek, 'mousedown mousemove', event => {
this.bind(elements.inputs.seek, 'mousedown mousemove', (event) => {
const rect = elements.progress.getBoundingClientRect();
const percent = (100 / rect.width) * (event.pageX - rect.left);
event.currentTarget.setAttribute('seek-value', percent);
});
// Pause while seeking
this.bind(elements.inputs.seek, 'mousedown mouseup keydown keyup touchstart touchend', event => {
this.bind(elements.inputs.seek, 'mousedown mouseup keydown keyup touchstart touchend', (event) => {
const seek = event.currentTarget;
const code = event.keyCode ? event.keyCode : event.which;
const attribute = 'play-on-seeked';
@@ -715,14 +738,14 @@ class Listeners {
// it takes over further interactions on the page. This is a hack
if (browser.isIos) {
const inputs = getElements.call(player, 'input[type="range"]');
Array.from(inputs).forEach(input => this.bind(input, inputEvent, event => repaint(event.target)));
Array.from(inputs).forEach((input) => this.bind(input, inputEvent, (event) => repaint(event.target)));
}
// Seek
this.bind(
elements.inputs.seek,
inputEvent,
event => {
(event) => {
const seek = event.currentTarget;
// If it exists, use seek-value instead of "value" for consistency with tooltip time (#954)
let seekTo = seek.getAttribute('seek-value');
@@ -739,13 +762,13 @@ class Listeners {
);
// Seek tooltip
this.bind(elements.progress, 'mouseenter mouseleave mousemove', event =>
this.bind(elements.progress, 'mouseenter mouseleave mousemove', (event) =>
controls.updateSeekTooltip.call(player, event),
);
// Preview thumbnails plugin
// TODO: Really need to work on some sort of plug-in wide event bus or pub-sub for this
this.bind(elements.progress, 'mousemove touchmove', event => {
this.bind(elements.progress, 'mousemove touchmove', (event) => {
const { previewThumbnails } = player;
if (previewThumbnails && previewThumbnails.loaded) {
@@ -763,7 +786,7 @@ class Listeners {
});
// Show scrubbing preview
this.bind(elements.progress, 'mousedown touchstart', event => {
this.bind(elements.progress, 'mousedown touchstart', (event) => {
const { previewThumbnails } = player;
if (previewThumbnails && previewThumbnails.loaded) {
@@ -771,7 +794,7 @@ class Listeners {
}
});
this.bind(elements.progress, 'mouseup touchend', event => {
this.bind(elements.progress, 'mouseup touchend', (event) => {
const { previewThumbnails } = player;
if (previewThumbnails && previewThumbnails.loaded) {
@@ -781,8 +804,8 @@ class Listeners {
// Polyfill for lower fill in <input type="range"> for webkit
if (browser.isWebkit) {
Array.from(getElements.call(player, 'input[type="range"]')).forEach(element => {
this.bind(element, 'input', event => controls.updateRangeFill.call(player, event.target));
Array.from(getElements.call(player, 'input[type="range"]')).forEach((element) => {
this.bind(element, 'input', (event) => controls.updateRangeFill.call(player, event.target));
});
}
@@ -805,30 +828,30 @@ class Listeners {
this.bind(
elements.inputs.volume,
inputEvent,
event => {
(event) => {
player.volume = event.target.value;
},
'volume',
);
// Update controls.hover state (used for ui.toggleControls to avoid hiding when interacting)
this.bind(elements.controls, 'mouseenter mouseleave', event => {
this.bind(elements.controls, 'mouseenter mouseleave', (event) => {
elements.controls.hover = !player.touch && event.type === 'mouseenter';
});
// Also update controls.hover state for any non-player children of fullscreen element (as above)
if (elements.fullscreen) {
Array.from(elements.fullscreen.children)
.filter(c => !c.contains(elements.container))
.forEach(child => {
this.bind(child, 'mouseenter mouseleave', event => {
.filter((c) => !c.contains(elements.container))
.forEach((child) => {
this.bind(child, 'mouseenter mouseleave', (event) => {
elements.controls.hover = !player.touch && event.type === 'mouseenter';
});
});
}
// Update controls.pressed state (used for ui.toggleControls to avoid hiding when interacting)
this.bind(elements.controls, 'mousedown mouseup touchstart touchend touchcancel', event => {
this.bind(elements.controls, 'mousedown mouseup touchstart touchend touchcancel', (event) => {
elements.controls.pressed = ['mousedown', 'touchstart'].includes(event.type);
});
@@ -861,12 +884,12 @@ class Listeners {
this.bind(
elements.inputs.volume,
'wheel',
event => {
(event) => {
// Detect "natural" scroll - suppored on OS X Safari only
// Other browsers on OS X will be inverted until support improves
const inverted = event.webkitDirectionInvertedFromDevice;
// Get delta from event. Invert if `inverted` is true
const [x, y] = [event.deltaX, -event.deltaY].map(value => (inverted ? -value : value));
const [x, y] = [event.deltaX, -event.deltaY].map((value) => (inverted ? -value : value));
// Using the biggest delta, normalize to 1 or -1 (or 0 if no delta)
const direction = Math.sign(Math.abs(x) > Math.abs(y) ? x : y);
+1
View File
@@ -41,6 +41,7 @@ const media = {
// Poster image container
this.elements.poster = createElement('div', {
class: this.config.classNames.poster,
hidden: '',
});
this.elements.wrapper.appendChild(this.elements.poster);
+10 -10
View File
@@ -15,7 +15,7 @@ import { silencePromise } from '../utils/promise';
import { formatTime } from '../utils/time';
import { buildUrlParams } from '../utils/urls';
const destroy = instance => {
const destroy = (instance) => {
// Destroy our adsManager
if (instance.manager) {
instance.manager.destroy();
@@ -179,10 +179,10 @@ class Ads {
// Listen and respond to ads loaded and error events
this.loader.addEventListener(
google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED,
event => this.onAdsManagerLoaded(event),
(event) => this.onAdsManagerLoaded(event),
false,
);
this.loader.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, error => this.onAdError(error), false);
this.loader.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, (error) => this.onAdError(error), false);
// Request video ads to be pre-loaded
this.requestAds();
@@ -264,11 +264,11 @@ class Ads {
// Add listeners to the required events
// Advertisement error events
this.manager.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, error => this.onAdError(error));
this.manager.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, (error) => this.onAdError(error));
// Advertisement regular events
Object.keys(google.ima.AdEvent.Type).forEach(type => {
this.manager.addEventListener(google.ima.AdEvent.Type[type], e => this.onAdEvent(e));
Object.keys(google.ima.AdEvent.Type).forEach((type) => {
this.manager.addEventListener(google.ima.AdEvent.Type[type], (e) => this.onAdEvent(e));
});
// Resolve our adsManager
@@ -278,7 +278,7 @@ class Ads {
addCuePoints() {
// Add advertisement cue's within the time line if available
if (!is.empty(this.cuePoints)) {
this.cuePoints.forEach(cuePoint => {
this.cuePoints.forEach((cuePoint) => {
if (cuePoint !== 0 && cuePoint !== -1 && cuePoint < this.player.duration) {
const seekElement = this.player.elements.progress;
@@ -310,7 +310,7 @@ class Ads {
const adData = event.getAdData();
// Proxy event
const dispatchEvent = type => {
const dispatchEvent = (type) => {
triggerEvent.call(this.player, this.player.media, `ads${type.replace(/_/g, '').toLowerCase()}`);
};
@@ -565,7 +565,7 @@ class Ads {
}
// Re-set our adsManager promises
this.managerPromise = new Promise(resolve => {
this.managerPromise = new Promise((resolve) => {
this.on('loaded', resolve);
this.player.debug.log(this.manager);
});
@@ -586,7 +586,7 @@ class Ads {
const handlers = this.events[event];
if (is.array(handlers)) {
handlers.forEach(handler => {
handlers.forEach((handler) => {
if (is.function(handler)) {
handler.apply(this, args);
}
+12 -12
View File
@@ -5,15 +5,15 @@ import is from '../utils/is';
import { formatTime } from '../utils/time';
// Arg: vttDataString example: "WEBVTT\n\n1\n00:00:05.000 --> 00:00:10.000\n1080p-00001.jpg"
const parseVtt = vttDataString => {
const parseVtt = (vttDataString) => {
const processedList = [];
const frames = vttDataString.split(/\r\n\r\n|\n\n|\r\r/);
frames.forEach(frame => {
frames.forEach((frame) => {
const result = {};
const lines = frame.split(/\r\n|\n|\r/);
lines.forEach(line => {
lines.forEach((line) => {
if (!is.number(result.startTime)) {
// The line with start and end times on it is the first line of interest
const matchTimes = line.match(
@@ -130,7 +130,7 @@ class PreviewThumbnails {
// Download VTT files and parse them
getThumbnails() {
return new Promise(resolve => {
return new Promise((resolve) => {
const { src } = this.player.config.previewThumbnails;
if (is.empty(src)) {
@@ -149,7 +149,7 @@ class PreviewThumbnails {
// Via callback()
if (is.function(src)) {
src(thumbnails => {
src((thumbnails) => {
this.thumbnails = thumbnails;
sortAndResolve();
});
@@ -159,7 +159,7 @@ class PreviewThumbnails {
// If string, convert into single-element list
const urls = is.string(src) ? [src] : src;
// Loop through each src URL. Download and process the VTT file, storing the resulting data in this.thumbnails
const promises = urls.map(u => this.getThumbnail(u));
const promises = urls.map((u) => this.getThumbnail(u));
// Resolve
Promise.all(promises).then(sortAndResolve);
}
@@ -168,8 +168,8 @@ class PreviewThumbnails {
// Process individual VTT file
getThumbnail(url) {
return new Promise(resolve => {
fetch(url).then(response => {
return new Promise((resolve) => {
fetch(url).then((response) => {
const thumbnail = {
frames: parseVtt(response),
height: null,
@@ -360,7 +360,7 @@ class PreviewThumbnails {
// Find the desired thumbnail index
// TODO: Handle a video longer than the thumbs where thumbNum is null
const thumbNum = this.thumbnails[0].frames.findIndex(
frame => this.seekTime >= frame.startTime && this.seekTime <= frame.endTime,
(frame) => this.seekTime >= frame.startTime && this.seekTime <= frame.endTime,
);
const hasThumb = thumbNum >= 0;
let qualityIndex = 0;
@@ -454,7 +454,7 @@ class PreviewThumbnails {
// Remove all preview images that aren't the designated current image
removeOldImages(currentImage) {
// Get a list of all images, convert it from a DOM list to an array
Array.from(this.currentImageContainer.children).forEach(image => {
Array.from(this.currentImageContainer.children).forEach((image) => {
if (image.tagName.toLowerCase() !== 'img') {
return;
}
@@ -481,7 +481,7 @@ class PreviewThumbnails {
// Preload images before and after the current one. Only if the user is still hovering/seeking the same frame
// This will only preload the lowest quality
preloadNearby(thumbNum, forward = true) {
return new Promise(resolve => {
return new Promise((resolve) => {
setTimeout(() => {
const oldThumbFilename = this.thumbnails[0].frames[thumbNum].text;
@@ -496,7 +496,7 @@ class PreviewThumbnails {
let foundOne = false;
thumbnailsClone.forEach(frame => {
thumbnailsClone.forEach((frame) => {
const newThumbFilename = frame.text;
if (newThumbFilename !== oldThumbFilename) {
+33 -33
View File
@@ -58,7 +58,7 @@ const vimeo = {
.then(() => {
vimeo.ready.call(player);
})
.catch(error => {
.catch((error) => {
player.debug.warn('Vimeo SDK (player.js) failed to load', error);
});
} else {
@@ -112,31 +112,29 @@ const vimeo = {
}
// Inject the package
const { poster } = player;
if (premium) {
iframe.setAttribute('data-poster', poster);
if (premium || !config.customControls) {
iframe.setAttribute('data-poster', player.poster);
player.media = replaceElement(iframe, player.media);
} else {
const wrapper = createElement('div', { class: player.config.classNames.embedContainer, 'data-poster': poster });
const wrapper = createElement('div', {
class: player.config.classNames.embedContainer,
'data-poster': player.poster,
});
wrapper.appendChild(iframe);
player.media = replaceElement(wrapper, player.media);
}
// Get poster image
fetch(format(player.config.urls.vimeo.api, id), 'json').then(response => {
if (is.empty(response)) {
return;
}
if (!config.customControls) {
fetch(format(player.config.urls.vimeo.api, src)).then((response) => {
if (is.empty(response) || !response.thumbnail_url) {
return;
}
// Get the URL for thumbnail
const url = new URL(response[0].thumbnail_large);
// Get original image
url.pathname = `${url.pathname.split('_')[0]}.jpg`;
// Set and show poster
ui.setPoster.call(player, url.href).catch(() => {});
});
// Set and show poster
ui.setPoster.call(player, response.thumbnail_url).catch(() => {});
});
}
// Setup instance
// https://github.com/vimeo/player.js
@@ -269,11 +267,11 @@ const vimeo = {
let currentSrc;
player.embed
.getVideoUrl()
.then(value => {
.then((value) => {
currentSrc = value;
controls.setDownloadUrl.call(player);
})
.catch(error => {
.catch((error) => {
this.debug.warn(error);
});
@@ -291,49 +289,49 @@ const vimeo = {
});
// 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;
player.embed.ratio = [width, height];
setAspectRatio.call(this);
});
// Set autopause
player.embed.setAutopause(player.config.autopause).then(state => {
player.embed.setAutopause(player.config.autopause).then((state) => {
player.config.autopause = state;
});
// Get title
player.embed.getVideoTitle().then(title => {
player.embed.getVideoTitle().then((title) => {
player.config.title = title;
ui.setTitle.call(this);
});
// Get current time
player.embed.getCurrentTime().then(value => {
player.embed.getCurrentTime().then((value) => {
currentTime = value;
triggerEvent.call(player, player.media, 'timeupdate');
});
// Get duration
player.embed.getDuration().then(value => {
player.embed.getDuration().then((value) => {
player.media.duration = value;
triggerEvent.call(player, player.media, 'durationchange');
});
// Get captions
player.embed.getTextTracks().then(tracks => {
player.embed.getTextTracks().then((tracks) => {
player.media.textTracks = tracks;
captions.setup.call(player);
});
player.embed.on('cuechange', ({ cues = [] }) => {
const strippedCues = cues.map(cue => stripHTML(cue.text));
const strippedCues = cues.map((cue) => stripHTML(cue.text));
captions.updateCues.call(player, strippedCues);
});
player.embed.on('loaded', () => {
// Assure state and events are updated on autoplay
player.embed.getPaused().then(paused => {
player.embed.getPaused().then((paused) => {
assurePlaybackState.call(player, !paused);
if (!paused) {
triggerEvent.call(player, player.media, 'playing');
@@ -366,13 +364,13 @@ const vimeo = {
assurePlaybackState.call(player, false);
});
player.embed.on('timeupdate', data => {
player.embed.on('timeupdate', (data) => {
player.media.seeking = false;
currentTime = data.seconds;
triggerEvent.call(player, player.media, 'timeupdate');
});
player.embed.on('progress', data => {
player.embed.on('progress', (data) => {
player.media.buffered = data.percent;
triggerEvent.call(player, player.media, 'progress');
@@ -383,7 +381,7 @@ const vimeo = {
// Get duration as if we do it before load, it gives an incorrect value
// https://github.com/sampotts/plyr/issues/891
player.embed.getDuration().then(value => {
player.embed.getDuration().then((value) => {
if (value !== player.media.duration) {
player.media.duration = value;
triggerEvent.call(player, player.media, 'durationchange');
@@ -401,13 +399,15 @@ const vimeo = {
triggerEvent.call(player, player.media, 'ended');
});
player.embed.on('error', detail => {
player.embed.on('error', (detail) => {
player.media.error = detail;
triggerEvent.call(player, player.media, 'error');
});
// Rebuild UI
setTimeout(() => ui.build.call(player), 0);
if (config.customControls) {
setTimeout(() => ui.build.call(player), 0);
}
},
};
+38 -31
View File
@@ -70,7 +70,7 @@ const youtube = {
};
// Load the SDK
loadScript(this.config.urls.youtube.sdk).catch(error => {
loadScript(this.config.urls.youtube.sdk).catch((error) => {
this.debug.warn('YouTube API failed to load', error);
});
}
@@ -81,7 +81,7 @@ const youtube = {
const url = format(this.config.urls.youtube.api, videoId);
fetch(url)
.then(data => {
.then((data) => {
if (is.object(data)) {
const { title, height, width } = data;
@@ -104,6 +104,7 @@ const youtube = {
// API ready
ready() {
const player = this;
const config = player.config.youtube;
// Ignore already setup (race condition)
const currentId = player.media && player.media.getAttribute('id');
if (!is.empty(currentId) && currentId.startsWith('youtube-')) {
@@ -121,43 +122,46 @@ const youtube = {
// Replace the <iframe> with a <div> due to YouTube API issues
const videoId = parseId(source);
const id = generateId(player.provider);
// Get poster, if already set
const { poster } = player;
// Replace media element
const container = createElement('div', { id, 'data-poster': poster });
const container = createElement('div', { id, 'data-poster': config.customControls ? player.poster : undefined });
player.media = replaceElement(container, player.media);
// Id to poster wrapper
const posterSrc = s => `https://i.ytimg.com/vi/${videoId}/${s}default.jpg`;
// Only load the poster when using custom controls
if (config.customControls) {
const posterSrc = (s) => `https://i.ytimg.com/vi/${videoId}/${s}default.jpg`;
// Check thumbnail images in order of quality, but reject fallback thumbnails (120px wide)
loadImage(posterSrc('maxres'), 121) // Higest quality and unpadded
.catch(() => loadImage(posterSrc('sd'), 121)) // 480p padded 4:3
.catch(() => loadImage(posterSrc('hq'))) // 360p padded 4:3. Always exists
.then(image => ui.setPoster.call(player, image.src))
.then(src => {
// If the image is padded, use background-size "cover" instead (like youtube does too with their posters)
if (!src.includes('maxres')) {
player.elements.poster.style.backgroundSize = 'cover';
}
})
.catch(() => {});
const config = player.config.youtube;
// Check thumbnail images in order of quality, but reject fallback thumbnails (120px wide)
loadImage(posterSrc('maxres'), 121) // Higest quality and unpadded
.catch(() => loadImage(posterSrc('sd'), 121)) // 480p padded 4:3
.catch(() => loadImage(posterSrc('hq'))) // 360p padded 4:3. Always exists
.then((image) => ui.setPoster.call(player, image.src))
.then((src) => {
// If the image is padded, use background-size "cover" instead (like youtube does too with their posters)
if (!src.includes('maxres')) {
player.elements.poster.style.backgroundSize = 'cover';
}
})
.catch(() => {});
}
// Setup instance
// https://developers.google.com/youtube/iframe_api_reference
player.embed = new window.YT.Player(id, {
player.embed = new window.YT.Player(player.media, {
videoId,
host: getHost(config),
playerVars: extend(
{},
{
autoplay: player.config.autoplay ? 1 : 0, // Autoplay
hl: player.config.hl, // iframe interface language
controls: player.supported.ui ? 0 : 1, // Only show controls if not fully supported
disablekb: 1, // Disable keyboard as we handle it
playsinline: !player.config.fullscreen.iosNative ? 1 : 0, // Allow iOS inline playback
// Autoplay
autoplay: player.config.autoplay ? 1 : 0,
// iframe interface language
hl: player.config.hl,
// Only show controls if not fully supported or opted out
controls: player.supported.ui && config.customControls ? 0 : 1,
// Disable keyboard as we handle it
disablekb: 1,
// Allow iOS inline playback
playsinline: !player.config.fullscreen.iosNative ? 1 : 0,
// Captions are flaky on YouTube
cc_load_policy: player.captions.active ? 1 : 0,
cc_lang_pref: player.config.captions.language,
@@ -278,6 +282,7 @@ const youtube = {
const toggle = is.boolean(input) ? input : muted;
muted = toggle;
instance[toggle ? 'mute' : 'unMute']();
instance.setVolume(volume * 100);
triggerEvent.call(player, player.media, 'volumechange');
},
});
@@ -299,10 +304,10 @@ const youtube = {
// Get available speeds
const speeds = instance.getAvailablePlaybackRates();
// Filter based on config
player.options.speed = speeds.filter(s => player.config.speed.options.includes(s));
player.options.speed = speeds.filter((s) => player.config.speed.options.includes(s));
// Set the tabindex to avoid focus entering iframe
if (player.supported.ui) {
if (player.supported.ui && config.customControls) {
player.media.setAttribute('tabindex', -1);
}
@@ -335,7 +340,9 @@ const youtube = {
}, 200);
// Rebuild UI
setTimeout(() => ui.build.call(player), 50);
if (config.customControls) {
setTimeout(() => ui.build.call(player), 50);
}
},
onStateChange(event) {
// Get the instance
@@ -386,7 +393,7 @@ const youtube = {
case 1:
// Restore paused state (YouTube starts playing on seek if the video hasn't been played yet)
if (!player.config.autoplay && player.media.paused && !player.embed.hasPlayed) {
if (config.customControls && !player.config.autoplay && player.media.paused && !player.embed.hasPlayed) {
player.media.pause();
} else {
assurePlaybackState.call(player, true);
+67 -46
View File
@@ -214,26 +214,17 @@ declare class Plyr {
/**
* Add an event listener for the specified event.
*/
on(
event: Plyr.StandardEvent | Plyr.Html5Event | Plyr.YoutubeEvent,
callback: (this: this, event: Plyr.PlyrEvent) => void,
): void;
on<K extends keyof Plyr.PlyrEventMap>(event: K, callback: (this: this, event: Plyr.PlyrEventMap[K]) => void): void;
/**
* Add an event listener for the specified event once.
*/
once(
event: Plyr.StandardEvent | Plyr.Html5Event | Plyr.YoutubeEvent,
callback: (this: this, event: Plyr.PlyrEvent) => void,
): void;
once<K extends keyof Plyr.PlyrEventMap>(event: K, callback: (this: this, event: Plyr.PlyrEventMap[K]) => void): void;
/**
* Remove an event listener for the specified event.
*/
off(
event: Plyr.StandardEvent | Plyr.Html5Event | Plyr.YoutubeEvent,
callback: (this: this, event: Plyr.PlyrEvent) => void,
): void;
off<K extends keyof Plyr.PlyrEventMap>(event: K, callback: (this: this, event: Plyr.PlyrEventMap[K]) => void): void;
/**
* Check support for a mime type.
@@ -249,37 +240,51 @@ declare class Plyr {
declare namespace Plyr {
type MediaType = 'audio' | 'video';
type Provider = 'html5' | 'youtube' | 'vimeo';
type StandardEvent =
| 'progress'
| 'playing'
| 'play'
| 'pause'
| 'timeupdate'
| 'volumechange'
| 'seeking'
| 'seeked'
| 'ratechange'
| 'ended'
| 'enterfullscreen'
| 'exitfullscreen'
| 'captionsenabled'
| 'captionsdisabled'
| 'languagechange'
| 'controlshidden'
| 'controlsshown'
| 'ready';
type Html5Event =
| 'loadstart'
| 'loadeddata'
| 'loadedmetadata'
| 'canplay'
| 'canplaythrough'
| 'stalled'
| 'waiting'
| 'emptied'
| 'cuechange'
| 'error';
type YoutubeEvent = 'statechange' | 'qualitychange' | 'qualityrequested';
type StandardEventMap = {
progress: PlyrEvent;
playing: PlyrEvent;
play: PlyrEvent;
pause: PlyrEvent;
timeupdate: PlyrEvent;
volumechange: PlyrEvent;
seeking: PlyrEvent;
seeked: PlyrEvent;
ratechange: PlyrEvent;
ended: PlyrEvent;
enterfullscreen: PlyrEvent;
exitfullscreen: PlyrEvent;
captionsenabled: PlyrEvent;
captionsdisabled: PlyrEvent;
languagechange: PlyrEvent;
controlshidden: PlyrEvent;
controlsshown: PlyrEvent;
ready: PlyrEvent;
};
// For retrocompatibility, we keep StandadEvent
type StandadEvent = keyof Plyr.StandardEventMap;
type Html5EventMap = {
loadstart: PlyrEvent;
loadeddata: PlyrEvent;
loadedmetadata: PlyrEvent;
canplay: PlyrEvent;
canplaythrough: PlyrEvent;
stalled: PlyrEvent;
waiting: PlyrEvent;
emptied: PlyrEvent;
cuechange: PlyrEvent;
error: PlyrEvent;
};
// For retrocompatibility, we keep Html5Event
type Html5Event = keyof Plyr.Html5EventMap;
type YoutubeEventMap = {
statechange: PlyrStateChangeEvent;
qualitychange: PlyrEvent;
qualityrequested: PlyrEvent;
};
// For retrocompatibility, we keep YoutubeEvent
type YoutubeEvent = keyof Plyr.YoutubeEventMap;
type PlyrEventMap = StandardEventMap & Html5EventMap & YoutubeEventMap;
interface FullscreenControl {
/**
@@ -357,7 +362,7 @@ declare namespace Plyr {
/**
* Specify a URL or path to a blank video file used to properly cancel network requests.
*/
blankUrl?: string;
blankVideo?: string;
/**
* Autoplay the media on load. This is generally advised against on UX grounds. It is also disabled by default in some browsers.
@@ -534,7 +539,7 @@ declare namespace Plyr {
interface FullScreenOptions {
enabled?: boolean;
fallback?: boolean;
fallback?: boolean | 'force';
allowAudio?: boolean;
iosNative?: boolean;
}
@@ -552,7 +557,7 @@ declare namespace Plyr {
interface PreviewThumbnailsOptions {
enabled?: boolean;
src?: string;
src?: string | string[];
}
interface SourceInfo {
@@ -623,6 +628,22 @@ declare namespace Plyr {
readonly detail: { readonly plyr: Plyr };
}
enum YoutubeState {
UNSTARTED = -1,
ENDED = 0,
PLAYING = 1,
PAUSED = 2,
BUFFERING = 3,
CUED = 5,
}
interface PlyrStateChangeEvent extends CustomEvent {
readonly detail: {
readonly plyr: Plyr;
readonly code: YoutubeState;
};
}
interface Support {
api: boolean;
ui: boolean;
+14 -5
View File
@@ -1,6 +1,6 @@
// ==========================================================================
// Plyr
// plyr.js v3.6.2
// plyr.js v3.6.3
// https://github.com/sampotts/plyr
// License: The MIT License (MIT)
// ==========================================================================
@@ -12,6 +12,7 @@ import { getProviderByUrl, providers, types } from './config/types';
import Console from './console';
import controls from './controls';
import Fullscreen from './fullscreen';
import html5 from './html5';
import Listeners from './listeners';
import media from './media';
import Ads from './plugins/ads';
@@ -281,7 +282,7 @@ class Plyr {
// Listen for events if debugging
if (this.config.debug) {
on.call(this, this.elements.container, this.config.events.join(' '), event => {
on.call(this, this.elements.container, this.config.events.join(' '), (event) => {
this.debug.log(`event: ${event.type}`);
});
}
@@ -308,7 +309,7 @@ class Plyr {
// Autoplay if required
if (this.isHTML5 && this.config.autoplay) {
setTimeout(() => silencePromise(this.play()), 10);
this.once('canplay', () => silencePromise(this.play()));
}
// Seek time will be recorded (in listeners.js) so we can prevent hiding controls for a few seconds after seek
@@ -1054,7 +1055,12 @@ class Plyr {
const hiding = toggleClass(this.elements.container, this.config.classNames.hideControls, force);
// Close menu
if (hiding && is.array(this.config.controls) && this.config.controls.includes('settings') && !is.empty(this.config.settings)) {
if (
hiding &&
is.array(this.config.controls) &&
this.config.controls.includes('settings') &&
!is.empty(this.config.settings)
) {
controls.toggleMenu.call(this, false);
}
@@ -1140,6 +1146,9 @@ class Plyr {
// Unbind listeners
unbindListeners.call(this);
// Cancel current network requests
html5.cancelRequests.call(this);
// Replace the container with the original element provided
replaceElement(this.elements.original, this.elements.container);
@@ -1248,7 +1257,7 @@ class Plyr {
return null;
}
return targets.map(t => new Plyr(t, options));
return targets.map((t) => new Plyr(t, options));
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
// ==========================================================================
// Plyr Polyfilled Build
// plyr.js v3.6.2
// plyr.js v3.6.3
// https://github.com/sampotts/plyr
// License: The MIT License (MIT)
// ==========================================================================
+1 -1
View File
@@ -20,7 +20,7 @@ const source = {
src: attributes,
});
} else if (is.array(attributes)) {
attributes.forEach(attribute => {
attributes.forEach((attribute) => {
insertElement(type, this.media, attribute);
});
}
+8 -5
View File
@@ -135,7 +135,7 @@ const ui = {
}
// If there's a play button, set label
Array.from(this.elements.buttons.play || []).forEach(button => {
Array.from(this.elements.buttons.play || []).forEach((button) => {
button.setAttribute('aria-label', label);
});
@@ -172,13 +172,16 @@ const ui = {
// Set property synchronously to respect the call order
this.media.setAttribute('data-poster', poster);
// Show the poster
this.elements.poster.removeAttribute('hidden');
// Wait until ui is ready
return (
ready
.call(this)
// Load image
.then(() => loadImage(poster))
.catch(err => {
.catch((err) => {
// Hide poster on error unless it's been set by another call
if (poster === this.poster) {
ui.togglePoster.call(this, false);
@@ -214,7 +217,7 @@ const ui = {
toggleClass(this.elements.container, this.config.classNames.stopped, this.stopped);
// Set state
Array.from(this.elements.buttons.play || []).forEach(target => {
Array.from(this.elements.buttons.play || []).forEach((target) => {
Object.assign(target, { pressed: this.playing });
target.setAttribute('aria-label', i18n.get(this.playing ? 'pause' : 'play', this.config));
});
@@ -270,8 +273,8 @@ const ui = {
// Loop through values (as they are the keys when the object is spread 🤔)
Object.values({ ...this.media.style })
// We're only fussed about Plyr specific properties
.filter(key => !is.empty(key) && key.startsWith('--plyr'))
.forEach(key => {
.filter((key) => !is.empty(key) && is.string(key) && key.startsWith('--plyr'))
.forEach((key) => {
// Set on the container
this.elements.container.style.setProperty(key, this.media.style.getPropertyValue(key));
+1 -1
View File
@@ -14,7 +14,7 @@ export const transitionEndEvent = (() => {
transition: 'transitionend',
};
const type = Object.keys(events).find(event => element.style[event] !== undefined);
const type = Object.keys(events).find((event) => element.style[event] !== undefined);
return is.string(type) ? events[type] : false;
})();
+2 -2
View File
@@ -138,7 +138,7 @@ export function getAttributesFromSelector(sel, existingAttributes) {
const attributes = {};
const existing = extend({}, existingAttributes);
sel.split(',').forEach(s => {
sel.split(',').forEach((s) => {
// Remove whitespace
const selector = s.trim();
const className = selector.replace('.', '');
@@ -198,7 +198,7 @@ export function toggleHidden(element, hidden) {
// Mirror Element.classList.toggle, with IE compatibility for "force" argument
export function toggleClass(element, className, force) {
if (is.nodeList(element)) {
return Array.from(element).map(e => toggleClass(e, className, force));
return Array.from(element).map((e) => toggleClass(e, className, force));
}
if (is.element(element)) {
+3 -3
View File
@@ -50,7 +50,7 @@ export function toggleListener(element, event, callback, toggle = false, passive
}
// If a single node is passed, bind the event listener
events.forEach(type => {
events.forEach((type) => {
if (this && this.eventListeners && toggle) {
// Cache event listener
this.eventListeners.push({ element, type, callback, options });
@@ -100,7 +100,7 @@ export function triggerEvent(element, type = '', bubbles = false, detail = {}) {
// Unbind all cached event listeners
export function unbindListeners() {
if (this && this.eventListeners) {
this.eventListeners.forEach(item => {
this.eventListeners.forEach((item) => {
const { element, type, callback, options } = item;
element.removeEventListener(type, callback, options);
});
@@ -111,7 +111,7 @@ export function unbindListeners() {
// Run method when / if player is ready
export function ready() {
return new Promise(resolve =>
return new Promise((resolve) =>
this.ready ? setTimeout(resolve, 0) : on.call(this, this.elements.container, 'ready', resolve),
).then(() => {});
}
+19 -19
View File
@@ -2,31 +2,31 @@
// Type checking utils
// ==========================================================================
const getConstructor = input => (input !== null && typeof input !== 'undefined' ? input.constructor : null);
const getConstructor = (input) => (input !== null && typeof input !== 'undefined' ? input.constructor : null);
const instanceOf = (input, constructor) => Boolean(input && constructor && input instanceof constructor);
const isNullOrUndefined = input => input === null || typeof input === 'undefined';
const isObject = input => getConstructor(input) === Object;
const isNumber = input => getConstructor(input) === Number && !Number.isNaN(input);
const isString = input => getConstructor(input) === String;
const isBoolean = input => getConstructor(input) === Boolean;
const isFunction = input => getConstructor(input) === Function;
const isArray = input => Array.isArray(input);
const isWeakMap = input => instanceOf(input, WeakMap);
const isNodeList = input => instanceOf(input, NodeList);
const isElement = input => instanceOf(input, Element);
const isTextNode = input => getConstructor(input) === Text;
const isEvent = input => instanceOf(input, Event);
const isKeyboardEvent = input => instanceOf(input, KeyboardEvent);
const isCue = input => instanceOf(input, window.TextTrackCue) || instanceOf(input, window.VTTCue);
const isTrack = input => instanceOf(input, TextTrack) || (!isNullOrUndefined(input) && isString(input.kind));
const isPromise = input => instanceOf(input, Promise) && isFunction(input.then);
const isNullOrUndefined = (input) => input === null || typeof input === 'undefined';
const isObject = (input) => getConstructor(input) === Object;
const isNumber = (input) => getConstructor(input) === Number && !Number.isNaN(input);
const isString = (input) => getConstructor(input) === String;
const isBoolean = (input) => getConstructor(input) === Boolean;
const isFunction = (input) => getConstructor(input) === Function;
const isArray = (input) => Array.isArray(input);
const isWeakMap = (input) => instanceOf(input, WeakMap);
const isNodeList = (input) => instanceOf(input, NodeList);
const isElement = (input) => instanceOf(input, Element);
const isTextNode = (input) => getConstructor(input) === Text;
const isEvent = (input) => instanceOf(input, Event);
const isKeyboardEvent = (input) => instanceOf(input, KeyboardEvent);
const isCue = (input) => instanceOf(input, window.TextTrackCue) || instanceOf(input, window.VTTCue);
const isTrack = (input) => instanceOf(input, TextTrack) || (!isNullOrUndefined(input) && isString(input.kind));
const isPromise = (input) => instanceOf(input, Promise) && isFunction(input.then);
const isEmpty = input =>
const isEmpty = (input) =>
isNullOrUndefined(input) ||
((isString(input) || isArray(input) || isNodeList(input)) && !input.length) ||
(isObject(input) && !Object.keys(input).length);
const isUrl = input => {
const isUrl = (input) => {
// Accept a URL object
if (instanceOf(input, window.URL)) {
return true;
+1 -1
View File
@@ -54,7 +54,7 @@ export default function loadSprite(url, id) {
// Get the sprite
fetch(url)
.then(result => {
.then((result) => {
if (is.empty(result)) {
return;
}
+1 -1
View File
@@ -26,7 +26,7 @@ export function extend(target = {}, ...sources) {
return target;
}
Object.keys(source).forEach(key => {
Object.keys(source).forEach((key) => {
if (is.object(source[key])) {
if (!Object.keys(target).includes(key)) {
Object.assign(target, { [key]: {} });
+1 -1
View File
@@ -33,7 +33,7 @@ export const replaceAll = (input = '', find = '', replace = '') =>
// Convert to title case
export const toTitleCase = (input = '') =>
input.toString().replace(/\w\S*/g, text => text.charAt(0).toUpperCase() + text.substr(1).toLowerCase());
input.toString().replace(/\w\S*/g, (text) => text.charAt(0).toUpperCase() + text.substr(1).toLowerCase());
// Convert string to pascalCase
export function toPascalCase(input = '') {
+6 -2
View File
@@ -27,7 +27,7 @@ export function reduceAspectRatio(ratio) {
}
export function getAspectRatio(input) {
const parse = ratio => (validateRatio(ratio) ? ratio.split(':').map(Number) : null);
const parse = (ratio) => (validateRatio(ratio) ? ratio.split(':').map(Number) : null);
// Try provided ratio
let ratio = parse(input);
@@ -68,7 +68,11 @@ export function setAspectRatio(input) {
const height = (100 / this.media.offsetWidth) * parseInt(window.getComputedStyle(this.media).paddingBottom, 10);
const offset = (height - padding) / (height / 50);
this.media.style.transform = `translateY(-${offset}%)`;
if (this.fullscreen.active) {
wrapper.style.paddingBottom = null;
} else {
this.media.style.transform = `translateY(-${offset}%)`;
}
} else if (this.isHTML5) {
wrapper.classList.toggle(this.config.classNames.videoFixedRatio, ratio !== null);
}
+4 -4
View File
@@ -5,9 +5,9 @@
import is from './is';
// Time helpers
export const getHours = value => Math.trunc((value / 60 / 60) % 60, 10);
export const getMinutes = value => Math.trunc((value / 60) % 60, 10);
export const getSeconds = value => Math.trunc(value % 60, 10);
export const getHours = (value) => Math.trunc((value / 60 / 60) % 60, 10);
export const getMinutes = (value) => Math.trunc((value / 60) % 60, 10);
export const getSeconds = (value) => Math.trunc(value % 60, 10);
// Format time to UI friendly string
export function formatTime(time = 0, displayHours = false, inverted = false) {
@@ -17,7 +17,7 @@ export function formatTime(time = 0, displayHours = false, inverted = false) {
}
// Format time component to add leading zero
const format = value => `0${value}`.slice(-2);
const format = (value) => `0${value}`.slice(-2);
// Breakdown to hours, mins, secs
let hours = getHours(time);
const mins = getMinutes(time);
-1
View File
@@ -12,7 +12,6 @@
font-family: $plyr-font-family;
font-variant-numeric: tabular-nums; // Force monosace-esque number widths
font-weight: $plyr-font-weight-regular;
height: 100%;
line-height: $plyr-line-height;
max-width: 100%;
min-width: 200px;
+1 -1
View File
@@ -3,7 +3,6 @@
// --------------------------------------------------------------
.plyr--full-ui input[type='range'] {
// WebKit
-webkit-appearance: none; /* stylelint-disable-line */
background: transparent;
border: 0;
@@ -13,6 +12,7 @@
display: block;
height: calc((#{$plyr-range-thumb-active-shadow-width} * 2) + #{$plyr-range-thumb-height});
margin: 0;
min-width: 0;
padding: 0;
transition: box-shadow 0.3s ease;
width: 100%;
+1 -1
View File
@@ -14,7 +14,7 @@
margin-right: $plyr-control-spacing;
}
@media (max-width: calc(#{$plyr-bp-md} - 1)) {
@media (max-width: calc(#{$plyr-bp-md} - 1px)) {
display: none;
}
}
+5 -4
View File
@@ -30,6 +30,7 @@ const plumber = require('gulp-plumber');
const size = require('gulp-size');
const sourcemaps = require('gulp-sourcemaps');
const browserSync = require('browser-sync').create();
const gulpIf = require('gulp-if');
// Configs
const build = require('../build.json');
// Info from package
@@ -74,8 +75,8 @@ const tasks = {
const sizeOptions = { showFiles: true, gzip: true };
// Clean out /dist
gulp.task('clean', done => {
const dirs = [paths.plyr.output, paths.demo.output].map(dir => path.join(dir, '**/*'));
gulp.task('clean', (done) => {
const dirs = [paths.plyr.output, paths.demo.output].map((dir) => path.join(dir, '**/*'));
// Don't delete the mp4
dirs.push(`!${path.join(paths.plyr.output, '**/*.mp4')}`);
@@ -89,7 +90,7 @@ gulp.task('clean', done => {
Object.entries(build.js).forEach(([filename, entry]) => {
const { dist, formats, namespace, polyfill, src } = entry;
formats.forEach(format => {
formats.forEach((format) => {
const name = `js:${filename}:${format}`;
const extension = format === 'es' ? 'mjs' : 'js';
tasks.js.push(name);
@@ -128,7 +129,7 @@ Object.entries(build.js).forEach(([filename, entry]) => {
},
),
)
.pipe(header('typeof navigator === "object" && ')) // "Support" SSR (#935)
.pipe(gulpIf(() => extension !== 'mjs', header('typeof navigator === "object" && '))) // "Support" SSR (#935)
.pipe(
rename({
extname: `.${extension}`,
+8 -8
View File
@@ -27,7 +27,7 @@ const { version } = pkg;
const minSuffix = '.min';
// Get AWS config
Object.values(deploy).forEach(target => {
Object.values(deploy).forEach((target) => {
Object.assign(target, {
publisher: publish.create({
region: target.region,
@@ -102,7 +102,7 @@ const localPath = new RegExp('(../)?dist/', 'gi');
const versionPath = `https://${deploy.cdn.domain}/${version}/`;
const cdnpath = new RegExp(`${deploy.cdn.domain}/${regex}/`, 'gi');
const renameFile = rename(p => {
const renameFile = rename((p) => {
p.basename = p.basename.replace(minSuffix, ''); // eslint-disable-line
p.dirname = p.dirname.replace('.', version); // eslint-disable-line
});
@@ -120,7 +120,7 @@ const canDeploy = () => {
return true;
};
gulp.task('version', done => {
gulp.task('version', (done) => {
if (!canDeploy()) {
done();
return null;
@@ -135,7 +135,7 @@ gulp.task('version', done => {
return gulp
.src(
files.map(file => path.join(root, `src/js/${file}`)),
files.map((file) => path.join(root, `src/js/${file}`)),
{ base: '.' },
)
.pipe(replace(semver, `v${version}`))
@@ -144,7 +144,7 @@ gulp.task('version', done => {
});
// Publish version to CDN bucket
gulp.task('cdn', done => {
gulp.task('cdn', (done) => {
if (!canDeploy()) {
done();
return null;
@@ -198,7 +198,7 @@ gulp.task('purge', () => {
.on('end', () => {
const purge = new FastlyPurge(fastly.token);
list.forEach(url => {
list.forEach((url) => {
log(`Purging ${ansi.cyan(url)}...`);
purge.url(url, (error, result) => {
@@ -213,7 +213,7 @@ gulp.task('purge', () => {
});
// Publish to demo bucket
gulp.task('demo', done => {
gulp.task('demo', (done) => {
if (!canDeploy()) {
done();
return null;
@@ -248,7 +248,7 @@ gulp.task('demo', done => {
.src(pages)
.pipe(replace(localPath, versionPath))
.pipe(
rename(p => {
rename((p) => {
if (options.demo.uploadPath) {
// eslint-disable-next-line no-param-reassign
p.dirname += options.demo.uploadPath;
+2077 -889
View File
File diff suppressed because it is too large Load Diff