Fullscreen API changes, color settings tweaks
This commit is contained in:
parent
d21b58e1c9
commit
73a39769d4
2
demo/dist/demo.css
vendored
2
demo/dist/demo.css
vendored
File diff suppressed because one or more lines are too long
@ -6,11 +6,11 @@
|
||||
.button,
|
||||
.button__count {
|
||||
align-items: center;
|
||||
background: #fff;
|
||||
background: $color-button-background;
|
||||
border: 0;
|
||||
border-radius: $border-radius-base;
|
||||
box-shadow: 0 1px 1px rgba(#000, 0.1);
|
||||
color: $gray;
|
||||
color: $color-button-text;
|
||||
display: inline-flex;
|
||||
padding: ($spacing-base * 0.75);
|
||||
position: relative;
|
||||
@ -71,7 +71,7 @@
|
||||
&::before {
|
||||
border: $arrow-size solid transparent;
|
||||
border-left-width: 0;
|
||||
border-right-color: #fff;
|
||||
border-right-color: $color-button-background;
|
||||
content: '';
|
||||
height: 0;
|
||||
position: absolute;
|
||||
|
@ -28,6 +28,7 @@ body {
|
||||
|
||||
main {
|
||||
margin: auto;
|
||||
padding-bottom: 1px; // Collapsing margins
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
@ -24,5 +24,9 @@ $color-vimeo: #19b7ed;
|
||||
$color-link: #fff;
|
||||
$color-background: $color-brand-primary;
|
||||
|
||||
// Buttons
|
||||
$color-button-background: #fff;
|
||||
$color-button-text: $gray;
|
||||
|
||||
// Focus
|
||||
$tab-focus-default-color: #fff;
|
||||
|
2
dist/plyr.css
vendored
2
dist/plyr.css
vendored
File diff suppressed because one or more lines are too long
2
dist/plyr.js
vendored
2
dist/plyr.js
vendored
File diff suppressed because one or more lines are too long
2
dist/plyr.js.map
vendored
2
dist/plyr.js.map
vendored
File diff suppressed because one or more lines are too long
@ -44,7 +44,7 @@
|
||||
"stylelint-order": "^0.8.0",
|
||||
"stylelint-scss": "^2.3.0",
|
||||
"stylelint-selector-bem-pattern": "^2.0.0",
|
||||
"uglify-es": "^3.3.9"
|
||||
"uglify-es": "^3.3.10"
|
||||
},
|
||||
"keywords": ["HTML5 Video", "HTML5 Audio", "Media Player", "DASH", "Shaka", "WordPress", "HLS"],
|
||||
"repository": {
|
||||
|
100
readme.md
100
readme.md
@ -304,69 +304,77 @@ element.addEventListener('ready', event => {
|
||||
|
||||
### Methods
|
||||
|
||||
Methods are not chainable. An example use of a method:
|
||||
Example method use:
|
||||
|
||||
```javascript
|
||||
player.play();
|
||||
player.play(); // Start playback
|
||||
player.fullscreen.enter(); // Enter fullscreen
|
||||
```
|
||||
|
||||
| Method | Parameters | Description |
|
||||
| ------------------------- | ---------------- | ---------------------------------------------------------------------------------------------------------- |
|
||||
| `play()`¹ | - | Start playback. |
|
||||
| `pause()` | - | Pause playback. |
|
||||
| `togglePlay(toggle)` | Boolean | Toggle playback, if no parameters are passed, it will toggle based on current status. |
|
||||
| `stop()` | - | Stop playback and reset to start. |
|
||||
| `restart()` | - | Restart playback. |
|
||||
| `rewind(seekTime)` | Number | Rewind playback by the specified seek time. If no parameter is passed, the default seek time will be used. |
|
||||
| `forward(seekTime)` | Number | Fast forward by the specified seek time. If no parameter is passed, the default seek time will be used. |
|
||||
| `increaseVolume(step)` | Number | Increase volume by the specified step. If no parameter is passed, the default step will be used. |
|
||||
| `decreaseVolume(step)` | Number | Increase volume by the specified step. If no parameter is passed, the default step will be used. |
|
||||
| `toggleCaptions(toggle)` | Boolean | Toggle captions display. If no parameter is passed, it will toggle based on current status. |
|
||||
| `toggleFullscreen(event)` | Event | Toggle fullscreen. Fullscreen can only be initiated by a user event. Exit is possible without user input. |
|
||||
| `airplay()` | - | Trigger the airplay dialog on supported devices. |
|
||||
| `toggleControls(toggle)` | Boolean | Toggle the controls based on the specified boolean. |
|
||||
| `on(event, function)` | String, Function | Add an event listener for the specified event. |
|
||||
| `off(event, function)` | String, Function | Remove an event listener for the specified event. |
|
||||
| `supports(type)` | String | Check support for a mime type. |
|
||||
| `destroy()` | - | Destroy the instance and garbage collect any elements. |
|
||||
| Method | Parameters | Description |
|
||||
| ------------------------ | ---------------- | ---------------------------------------------------------------------------------------------------------- |
|
||||
| `play()`¹ | - | Start playback. |
|
||||
| `pause()` | - | Pause playback. |
|
||||
| `togglePlay(toggle)` | Boolean | Toggle playback, if no parameters are passed, it will toggle based on current status. |
|
||||
| `stop()` | - | Stop playback and reset to start. |
|
||||
| `restart()` | - | Restart playback. |
|
||||
| `rewind(seekTime)` | Number | Rewind playback by the specified seek time. If no parameter is passed, the default seek time will be used. |
|
||||
| `forward(seekTime)` | Number | Fast forward by the specified seek time. If no parameter is passed, the default seek time will be used. |
|
||||
| `increaseVolume(step)` | Number | Increase volume by the specified step. If no parameter is passed, the default step will be used. |
|
||||
| `decreaseVolume(step)` | Number | Increase volume by the specified step. If no parameter is passed, the default step will be used. |
|
||||
| `toggleCaptions(toggle)` | Boolean | Toggle captions display. If no parameter is passed, it will toggle based on current status. |
|
||||
| `fullscreen.enter()` | - | Enter fullscreen. If fullscreen is not supported, a fallback "full window/viewport" is used instead. |
|
||||
| `fullscreen.exit()` | - | Exit fullscreen. |
|
||||
| `fullscreen.toggle()` | - | Toggle fullscreen. |
|
||||
| `airplay()` | - | Trigger the airplay dialog on supported devices. |
|
||||
| `toggleControls(toggle)` | Boolean | Toggle the controls based on the specified boolean. |
|
||||
| `on(event, function)` | String, Function | Add an event listener for the specified event. |
|
||||
| `off(event, function)` | String, Function | Remove an event listener for the specified event. |
|
||||
| `supports(type)` | String | Check support for a mime type. |
|
||||
| `destroy()` | - | Destroy the instance and garbage collect any elements. |
|
||||
|
||||
1. For HTML5 players, `play()` will return a [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) in _some_ browsers - WebKit and Mozilla [according to MDN](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/play) at time of writing.
|
||||
|
||||
### Getters and Setters
|
||||
|
||||
An example setter:
|
||||
Example setters:
|
||||
|
||||
```javascript
|
||||
player.volume = 0.5;
|
||||
player.volume = 0.5; // Sets volume at 50%
|
||||
player.currentTime = 10; // Seeks to 10 seconds
|
||||
```
|
||||
|
||||
An example getter:
|
||||
Example getters:
|
||||
|
||||
```javascript
|
||||
player.volume; // returns 0.5;
|
||||
player.volume; // 0.5;
|
||||
player.currentTime; // 10
|
||||
player.fullscreen.active; // false;
|
||||
```
|
||||
|
||||
| Property | Getter | Setter | Description |
|
||||
| --------------- | ------ | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `isHTML5` | ✓ | - | Returns a boolean indicating if the current player is HTML5. |
|
||||
| `isEmbed` | ✓ | - | Returns a boolean indicating if the current player is an embedded player. |
|
||||
| `paused` | ✓ | - | Returns a boolean indicating if the current player is paused. |
|
||||
| `playing` | ✓ | - | Returns a boolean indicating if the current player is playing. |
|
||||
| `ended` | ✓ | - | Returns a boolean indicating if the current player has finished playback. |
|
||||
| `currentTime` | ✓ | ✓ | Gets or sets the currentTime for the player. The setter accepts a float in seconds. |
|
||||
| `seeking` | ✓ | - | Returns a boolean indicating if the current player is seeking. |
|
||||
| `duration` | ✓ | - | Returns the duration for the current media. |
|
||||
| `volume` | ✓ | ✓ | Gets or sets the volume for the player. The setter accepts a float between 0 and 1. |
|
||||
| `muted` | ✓ | ✓ | Gets or sets the muted state of the player. The setter accepts a boolean. |
|
||||
| `hasAudio` | ✓ | - | Returns a boolean indicating if the current media has an audio track. |
|
||||
| `speed` | ✓ | ✓ | Gets or sets the speed for the player. The setter accepts a value in the options specified in your config. Generally the minimum should be 0.5. |
|
||||
| `quality`¹ | ✓ | ✓ | Gets or sets the quality for the player. The setter accepts a value from the options specified in your config. |
|
||||
| `loop` | ✓ | ✓ | Gets or sets the current loop state of the player. The setter accepts a boolean. |
|
||||
| `source` | ✓ | ✓ | Gets or sets the current source for the player. The setter accepts an object. See [source setter](#source-setter) below for examples. |
|
||||
| `poster`² | ✓ | ✓ | Gets or sets the current poster image for the player. The setter accepts a string; the URL for the updated poster image. |
|
||||
| `autoplay` | ✓ | ✓ | Gets or sets the autoplay state of the player. The setter accepts a boolean. |
|
||||
| `language` | ✓ | ✓ | Gets or sets the preferred captions language for the player. The setter accepts an ISO two-letter language code. Support for the languages is dependent on the captions you include. |
|
||||
| `pip` | ✓ | ✓ | Gets or sets the picture-in-picture state of the player. The setter accepts a boolean. This currently only supported on Safari 10+ on MacOS Sierra+ and iOS 10+. |
|
||||
| Property | Getter | Setter | Description |
|
||||
| -------------------- | ------ | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `isHTML5` | ✓ | - | Returns a boolean indicating if the current player is HTML5. |
|
||||
| `isEmbed` | ✓ | - | Returns a boolean indicating if the current player is an embedded player. |
|
||||
| `paused` | ✓ | - | Returns a boolean indicating if the current player is paused. |
|
||||
| `playing` | ✓ | - | Returns a boolean indicating if the current player is playing. |
|
||||
| `ended` | ✓ | - | Returns a boolean indicating if the current player has finished playback. |
|
||||
| `currentTime` | ✓ | ✓ | Gets or sets the currentTime for the player. The setter accepts a float in seconds. |
|
||||
| `seeking` | ✓ | - | Returns a boolean indicating if the current player is seeking. |
|
||||
| `duration` | ✓ | - | Returns the duration for the current media. |
|
||||
| `volume` | ✓ | ✓ | Gets or sets the volume for the player. The setter accepts a float between 0 and 1. |
|
||||
| `muted` | ✓ | ✓ | Gets or sets the muted state of the player. The setter accepts a boolean. |
|
||||
| `hasAudio` | ✓ | - | Returns a boolean indicating if the current media has an audio track. |
|
||||
| `speed` | ✓ | ✓ | Gets or sets the speed for the player. The setter accepts a value in the options specified in your config. Generally the minimum should be 0.5. |
|
||||
| `quality`¹ | ✓ | ✓ | Gets or sets the quality for the player. The setter accepts a value from the options specified in your config. |
|
||||
| `loop` | ✓ | ✓ | Gets or sets the current loop state of the player. The setter accepts a boolean. |
|
||||
| `source` | ✓ | ✓ | Gets or sets the current source for the player. The setter accepts an object. See [source setter](#source-setter) below for examples. |
|
||||
| `poster`² | ✓ | ✓ | Gets or sets the current poster image for the player. The setter accepts a string; the URL for the updated poster image. |
|
||||
| `autoplay` | ✓ | ✓ | Gets or sets the autoplay state of the player. The setter accepts a boolean. |
|
||||
| `language` | ✓ | ✓ | Gets or sets the preferred captions language for the player. The setter accepts an ISO two-letter language code. Support for the languages is dependent on the captions you include. |
|
||||
| `fullscreen.active` | ✓ | - | Returns a boolean indicating if the current player is in fullscreen mode. |
|
||||
| `fullscreen.enabled` | ✓ | - | Returns a boolean indicating if the current player has fullscreen enabled. |
|
||||
| `pip` | ✓ | ✓ | Gets or sets the picture-in-picture state of the player. The setter accepts a boolean. This currently only supported on Safari 10+ on MacOS Sierra+ and iOS 10+. |
|
||||
|
||||
1. YouTube only. HTML5 will follow.
|
||||
2. HTML5 only
|
||||
|
@ -120,6 +120,7 @@ const defaults = {
|
||||
fullscreen: {
|
||||
enabled: true, // Allow fullscreen?
|
||||
fallback: true, // Fallback for vintage browsers
|
||||
iosNative: false, // Use the native fullscreen in iOS (disables custom controls)
|
||||
},
|
||||
|
||||
// Local storage
|
||||
|
@ -1,127 +1,201 @@
|
||||
// ==========================================================================
|
||||
// Plyr fullscreen API
|
||||
// Fullscreen wrapper
|
||||
// ==========================================================================
|
||||
|
||||
import utils from './utils';
|
||||
|
||||
// Determine the prefix
|
||||
const prefix = (() => {
|
||||
let value = false;
|
||||
const browser = utils.getBrowser();
|
||||
|
||||
if (utils.is.function(document.cancelFullScreen)) {
|
||||
value = '';
|
||||
function onChange() {
|
||||
if (!this.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update toggle button
|
||||
const button = this.player.elements.buttons.fullscreen;
|
||||
if (utils.is.element(button)) {
|
||||
utils.toggleState(button, this.active);
|
||||
}
|
||||
|
||||
// Trigger an event
|
||||
utils.dispatchEvent(this.target, this.active ? 'enterfullscreen' : 'exitfullscreen', true);
|
||||
|
||||
// Trap focus in container
|
||||
if (!browser.isIos) {
|
||||
utils.trapFocus.call(this.player, this.target, this.active);
|
||||
}
|
||||
}
|
||||
|
||||
function toggleFallback(toggle = false) {
|
||||
// Store or restore scroll position
|
||||
if (toggle) {
|
||||
this.scrollPosition = {
|
||||
x: window.scrollX || 0,
|
||||
y: window.scrollY || 0,
|
||||
};
|
||||
} else {
|
||||
window.scrollTo(this.scrollPosition.x, this.scrollPosition.y);
|
||||
}
|
||||
|
||||
// Toggle scroll
|
||||
document.body.style.overflow = toggle ? 'hidden' : '';
|
||||
|
||||
// Toggle class hook
|
||||
utils.toggleClass(this.target, this.player.config.classNames.fullscreen.fallback, toggle);
|
||||
|
||||
// Toggle button and fire events
|
||||
onChange.call(this);
|
||||
}
|
||||
|
||||
class Fullscreen {
|
||||
constructor(player) {
|
||||
// Keep reference to parent
|
||||
this.player = player;
|
||||
|
||||
// Get prefix
|
||||
this.prefix = Fullscreen.prefix;
|
||||
|
||||
// Scroll position
|
||||
this.scrollPosition = { x: 0, y: 0 };
|
||||
|
||||
// Register event listeners
|
||||
// Handle event (incase user presses escape etc)
|
||||
utils.on(document, this.prefix === 'ms' ? 'MSFullscreenChange' : `${this.prefix}fullscreenchange`, () => {
|
||||
// TODO: Filter for target??
|
||||
onChange.call(this);
|
||||
});
|
||||
|
||||
// Fullscreen toggle on double click
|
||||
utils.on(this.player.elements.container, 'dblclick', () => {
|
||||
this.toggle();
|
||||
});
|
||||
|
||||
// Update the UI
|
||||
this.update();
|
||||
}
|
||||
|
||||
// Determine if native supported
|
||||
static get native() {
|
||||
return !!(document.fullscreenEnabled || document.webkitFullscreenEnabled || document.mozFullScreenEnabled || document.msFullscreenEnabled);
|
||||
}
|
||||
|
||||
// Get the prefix for handlers
|
||||
static get prefix() {
|
||||
// No prefix
|
||||
if (utils.is.function(document.cancelFullScreen)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for fullscreen support by vendor prefix
|
||||
[
|
||||
let value = '';
|
||||
const prefixes = [
|
||||
'webkit',
|
||||
'o',
|
||||
'moz',
|
||||
'ms',
|
||||
'khtml',
|
||||
].some(pre => {
|
||||
];
|
||||
|
||||
prefixes.some(pre => {
|
||||
if (utils.is.function(document[`${pre}CancelFullScreen`])) {
|
||||
value = pre;
|
||||
return true;
|
||||
} else if (utils.is.function(document.msExitFullscreen) && document.msFullscreenEnabled) {
|
||||
// Special case for MS (when isn't it?)
|
||||
} else if (utils.is.function(document.msExitFullscreen)) {
|
||||
value = 'ms';
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
return value;
|
||||
})();
|
||||
// Determine if fullscreen is enabled
|
||||
get enabled() {
|
||||
const fallback = this.player.config.fullscreen.fallback && !utils.inFrame();
|
||||
|
||||
// Fullscreen API
|
||||
const fullscreen = {
|
||||
// Get the prefix
|
||||
prefix,
|
||||
return (Fullscreen.native || fallback) && this.player.config.fullscreen.enabled && this.player.supported.ui && this.player.isVideo;
|
||||
}
|
||||
|
||||
// Check if we can use it
|
||||
enabled: document.fullscreenEnabled || document.webkitFullscreenEnabled || document.mozFullScreenEnabled || document.msFullscreenEnabled,
|
||||
|
||||
// Yet again Microsoft awesomeness,
|
||||
// Sometimes the prefix is 'ms', sometimes 'MS' to keep you on your toes
|
||||
eventType: prefix === 'ms' ? 'MSFullscreenChange' : `${prefix}fullscreenchange`,
|
||||
|
||||
// Is an element fullscreen
|
||||
isFullScreen(element) {
|
||||
if (!fullscreen.enabled) {
|
||||
// Get active state
|
||||
get active() {
|
||||
if (!this.enabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const target = utils.is.nullOrUndefined(element) ? document.body : element;
|
||||
|
||||
switch (prefix) {
|
||||
case '':
|
||||
return document.fullscreenElement === target;
|
||||
|
||||
case 'moz':
|
||||
return document.mozFullScreenElement === target;
|
||||
|
||||
default:
|
||||
return document[`${prefix}FullscreenElement`] === target;
|
||||
// Fallback using classname
|
||||
if (!Fullscreen.native) {
|
||||
return utils.hasClass(this.target, this.player.config.classNames.fullscreen.fallback);
|
||||
}
|
||||
},
|
||||
|
||||
const element = !this.prefix ? document.fullscreenElement : document[`${this.prefix}FullscreenElement`];
|
||||
|
||||
return element === this.target;
|
||||
}
|
||||
|
||||
// Get target element
|
||||
get target() {
|
||||
return browser.isIos && this.player.config.fullscreen.iosNative ? this.player.media : this.player.elements.container;
|
||||
}
|
||||
|
||||
// Update UI
|
||||
update() {
|
||||
if (this.enabled) {
|
||||
this.player.debug.log(`${Fullscreen.native ? 'Native' : 'Fallback'} fullscreen enabled`);
|
||||
} else {
|
||||
this.player.debug.log('Fullscreen not supported and fallback disabled');
|
||||
}
|
||||
|
||||
// Add styling hook to show button
|
||||
utils.toggleClass(this.player.elements.container, this.player.config.classNames.fullscreen.enabled, this.enabled);
|
||||
}
|
||||
|
||||
// Make an element fullscreen
|
||||
requestFullScreen(element) {
|
||||
if (!fullscreen.enabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const target = utils.is.nullOrUndefined(element) ? document.body : element;
|
||||
|
||||
return !prefix.length ? target.requestFullScreen() : target[prefix + (prefix === 'ms' ? 'RequestFullscreen' : 'RequestFullScreen')]();
|
||||
},
|
||||
|
||||
// Bail from fullscreen
|
||||
cancelFullScreen() {
|
||||
if (!fullscreen.enabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !prefix.length ? document.cancelFullScreen() : document[prefix + (prefix === 'ms' ? 'ExitFullscreen' : 'CancelFullScreen')]();
|
||||
},
|
||||
|
||||
// Get the current element
|
||||
element() {
|
||||
if (!fullscreen.enabled) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return !prefix.length ? document.fullscreenElement : document[`${prefix}FullscreenElement`];
|
||||
},
|
||||
|
||||
// Setup fullscreen
|
||||
setup() {
|
||||
if (!this.supported.ui || this.isAudio || !this.config.fullscreen.enabled) {
|
||||
enter() {
|
||||
if (!this.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for native support
|
||||
const nativeSupport = fullscreen.enabled;
|
||||
// iOS native fullscreen doesn't need the request step
|
||||
if (browser.isIos && this.player.config.fullscreen.iosNative) {
|
||||
if (this.player.playing) {
|
||||
this.target.webkitEnterFullscreen();
|
||||
}
|
||||
} else if (!Fullscreen.native) {
|
||||
toggleFallback.call(this, true);
|
||||
} else if (!this.prefix) {
|
||||
this.target.requestFullScreen();
|
||||
} else if (!utils.is.empty(this.prefix)) {
|
||||
this.target[`${this.prefix}${this.prefix === 'ms' ? 'RequestFullscreen' : 'RequestFullScreen'}`]();
|
||||
}
|
||||
}
|
||||
|
||||
if (nativeSupport || (this.config.fullscreen.fallback && !utils.inFrame())) {
|
||||
this.debug.log(`${nativeSupport ? 'Native' : 'Fallback'} fullscreen enabled`);
|
||||
// Bail from fullscreen
|
||||
exit() {
|
||||
if (!this.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add styling hook to show button
|
||||
utils.toggleClass(this.elements.container, this.config.classNames.fullscreen.enabled, true);
|
||||
// iOS native fullscreen
|
||||
if (browser.isIos && this.player.config.fullscreen.iosNative) {
|
||||
this.target.webkitExitFullscreen();
|
||||
this.player.play();
|
||||
} else if (!Fullscreen.native) {
|
||||
toggleFallback.call(this, false);
|
||||
} else if (!this.prefix) {
|
||||
document.cancelFullScreen();
|
||||
} else if (!utils.is.empty(this.prefix)) {
|
||||
document[`${this.prefix}${this.prefix === 'ms' ? 'ExitFullscreen' : 'CancelFullScreen'}`]();
|
||||
}
|
||||
}
|
||||
|
||||
// Toggle state
|
||||
toggle() {
|
||||
if (!this.active) {
|
||||
this.enter();
|
||||
} else {
|
||||
this.debug.log('Fullscreen not supported and fallback disabled');
|
||||
this.exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Toggle state
|
||||
if (this.elements.buttons && this.elements.buttons.fullscreen) {
|
||||
utils.toggleState(this.elements.buttons.fullscreen, false);
|
||||
}
|
||||
|
||||
// Trap focus in container
|
||||
utils.trapFocus.call(this);
|
||||
},
|
||||
};
|
||||
|
||||
export default fullscreen;
|
||||
export default Fullscreen;
|
||||
|
@ -5,7 +5,6 @@
|
||||
import support from './support';
|
||||
import utils from './utils';
|
||||
import controls from './controls';
|
||||
import fullscreen from './fullscreen';
|
||||
import ui from './ui';
|
||||
|
||||
// Sniff out the browser
|
||||
@ -138,7 +137,7 @@ const listeners = {
|
||||
|
||||
case 70:
|
||||
// F key
|
||||
this.toggleFullscreen();
|
||||
this.fullscreen.toggle();
|
||||
break;
|
||||
|
||||
case 67:
|
||||
@ -171,8 +170,8 @@ const listeners = {
|
||||
|
||||
// Escape is handle natively when in full screen
|
||||
// So we only need to worry about non native
|
||||
if (!fullscreen.enabled && this.fullscreen.active && code === 27) {
|
||||
this.toggleFullscreen();
|
||||
if (!this.fullscreen.enabled && this.fullscreen.active && code === 27) {
|
||||
this.fullscreen.toggle();
|
||||
}
|
||||
|
||||
// Store last code for next cycle
|
||||
@ -215,18 +214,6 @@ const listeners = {
|
||||
this.toggleControls(event);
|
||||
});
|
||||
}
|
||||
|
||||
// Handle user exiting fullscreen by escaping etc
|
||||
if (fullscreen.enabled) {
|
||||
utils.on(document, fullscreen.eventType, event => {
|
||||
this.toggleFullscreen(event);
|
||||
});
|
||||
|
||||
// Fullscreen toggle on double click
|
||||
utils.on(this.elements.container, 'dblclick', event => {
|
||||
this.toggleFullscreen(event);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// Listen for media events
|
||||
@ -266,7 +253,7 @@ const listeners = {
|
||||
utils.on(this.media, 'playing play pause ended', event => ui.checkPlaying.call(this, event));
|
||||
|
||||
// Loading
|
||||
utils.on(this.media, 'stalled waiting canplay seeked playing', event => ui.checkLoading.call(this, event));
|
||||
utils.on(this.media, 'waiting canplay seeked playing', event => ui.checkLoading.call(this, event));
|
||||
|
||||
// Check if media failed to load
|
||||
// utils.on(this.media, 'play', event => ui.checkFailed.call(this, event));
|
||||
@ -307,7 +294,7 @@ const listeners = {
|
||||
event => {
|
||||
event.preventDefault();
|
||||
},
|
||||
false
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
@ -394,63 +381,63 @@ const listeners = {
|
||||
utils.on(this.elements.buttons.play, 'click', event =>
|
||||
proxy(event, 'play', () => {
|
||||
this.togglePlay();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
// Pause
|
||||
utils.on(this.elements.buttons.restart, 'click', event =>
|
||||
proxy(event, 'restart', () => {
|
||||
this.restart();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
// Rewind
|
||||
utils.on(this.elements.buttons.rewind, 'click', event =>
|
||||
proxy(event, 'rewind', () => {
|
||||
this.rewind();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
// Rewind
|
||||
utils.on(this.elements.buttons.forward, 'click', event =>
|
||||
proxy(event, 'forward', () => {
|
||||
this.forward();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
// Mute toggle
|
||||
utils.on(this.elements.buttons.mute, 'click', event =>
|
||||
proxy(event, 'mute', () => {
|
||||
this.muted = !this.muted;
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
// Captions toggle
|
||||
utils.on(this.elements.buttons.captions, 'click', event =>
|
||||
proxy(event, 'captions', () => {
|
||||
this.toggleCaptions();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
// Fullscreen toggle
|
||||
utils.on(this.elements.buttons.fullscreen, 'click', event =>
|
||||
proxy(event, 'fullscreen', () => {
|
||||
this.toggleFullscreen();
|
||||
})
|
||||
this.fullscreen.toggle();
|
||||
}),
|
||||
);
|
||||
|
||||
// Picture-in-Picture
|
||||
utils.on(this.elements.buttons.pip, 'click', event =>
|
||||
proxy(event, 'pip', () => {
|
||||
this.pip = 'toggle';
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
// Airplay
|
||||
utils.on(this.elements.buttons.airplay, 'click', event =>
|
||||
proxy(event, 'airplay', () => {
|
||||
this.airplay();
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
// Settings menu
|
||||
@ -489,7 +476,7 @@ const listeners = {
|
||||
utils.on(this.elements.inputs.seek, inputEvent, event =>
|
||||
proxy(event, 'seek', () => {
|
||||
this.currentTime = event.target.value / event.target.max * this.duration;
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
// Current time invert
|
||||
@ -510,7 +497,7 @@ const listeners = {
|
||||
utils.on(this.elements.inputs.volume, inputEvent, event =>
|
||||
proxy(event, 'volume', () => {
|
||||
this.volume = event.target.value;
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
// Polyfill for lower fill in <input type="range"> for webkit
|
||||
@ -583,7 +570,7 @@ const listeners = {
|
||||
event.preventDefault();
|
||||
}
|
||||
}),
|
||||
false
|
||||
false,
|
||||
);
|
||||
},
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
// ==========================================================================
|
||||
// ==========================================================================
|
||||
// Plyr
|
||||
// plyr.js v3.0.0-beta.12
|
||||
// https://github.com/sampotts/plyr
|
||||
@ -11,12 +11,12 @@ import support from './support';
|
||||
import utils from './utils';
|
||||
|
||||
import Console from './console';
|
||||
import Fullscreen from './fullscreen';
|
||||
import Storage from './storage';
|
||||
import Ads from './plugins/ads';
|
||||
|
||||
import captions from './captions';
|
||||
import controls from './controls';
|
||||
import fullscreen from './fullscreen';
|
||||
import listeners from './listeners';
|
||||
import media from './media';
|
||||
import source from './source';
|
||||
@ -26,12 +26,6 @@ import ui from './ui';
|
||||
// TODO: Use a WeakMap for private globals
|
||||
// const globals = new WeakMap();
|
||||
|
||||
// Globals
|
||||
let scrollPosition = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
};
|
||||
|
||||
// Plyr instance
|
||||
class Plyr {
|
||||
constructor(target, options) {
|
||||
@ -232,9 +226,6 @@ class Plyr {
|
||||
return;
|
||||
}
|
||||
|
||||
// Setup local storage for user settings
|
||||
this.storage = new Storage(this);
|
||||
|
||||
// Check for support again but with type
|
||||
this.supported = support.check(this.type, this.provider, this.config.inline);
|
||||
|
||||
@ -244,6 +235,9 @@ class Plyr {
|
||||
return;
|
||||
}
|
||||
|
||||
// Setup local storage for user settings
|
||||
this.storage = new Storage(this);
|
||||
|
||||
// Store reference
|
||||
this.media.plyr = this;
|
||||
|
||||
@ -278,6 +272,9 @@ class Plyr {
|
||||
ui.build.call(this);
|
||||
}
|
||||
|
||||
// Setup fullscreen
|
||||
this.fullscreen = new Fullscreen(this);
|
||||
|
||||
// Setup ads if provided
|
||||
this.ads = new Ads(this);
|
||||
}
|
||||
@ -850,62 +847,6 @@ class Plyr {
|
||||
return this.captions.language;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle fullscreen playback
|
||||
* Requires user input event
|
||||
* @param {event} event
|
||||
*/
|
||||
toggleFullscreen(event) {
|
||||
// Video only
|
||||
if (this.isAudio) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for native support
|
||||
if (fullscreen.enabled) {
|
||||
if (utils.is.event(event) && event.type === fullscreen.eventType) {
|
||||
// If it's a fullscreen change event, update the state
|
||||
this.fullscreen.active = fullscreen.isFullScreen(this.elements.container);
|
||||
} else {
|
||||
// Else it's a user request to enter or exit
|
||||
if (!this.fullscreen.active) {
|
||||
fullscreen.requestFullScreen(this.elements.container);
|
||||
} else {
|
||||
fullscreen.cancelFullScreen();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Otherwise, it's a simple toggle
|
||||
this.fullscreen.active = !this.fullscreen.active;
|
||||
|
||||
// Add class hook
|
||||
utils.toggleClass(this.elements.container, this.config.classNames.fullscreen.fallback, this.fullscreen.active);
|
||||
|
||||
// Make sure we don't lose scroll position
|
||||
if (this.fullscreen.active) {
|
||||
scrollPosition = {
|
||||
x: window.pageXOffset || 0,
|
||||
y: window.pageYOffset || 0,
|
||||
};
|
||||
} else {
|
||||
window.scrollTo(scrollPosition.x, scrollPosition.y);
|
||||
}
|
||||
|
||||
// Bind/unbind escape key
|
||||
document.body.style.overflow = this.fullscreen.active ? 'hidden' : '';
|
||||
}
|
||||
|
||||
// Set button state
|
||||
if (utils.is.element(this.elements.buttons.fullscreen)) {
|
||||
utils.toggleState(this.elements.buttons.fullscreen, this.fullscreen.active);
|
||||
}
|
||||
|
||||
// Trigger an event
|
||||
utils.dispatchEvent.call(this, this.media, this.fullscreen.active ? 'enterfullscreen' : 'exitfullscreen');
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle picture-in-picture playback on WebKit/MacOS
|
||||
* TODO: update player with state, support, enabled
|
||||
|
@ -136,6 +136,9 @@ const source = {
|
||||
// Setup interface
|
||||
ui.build.call(this);
|
||||
}
|
||||
|
||||
// Update the fullscreen support
|
||||
this.fullscreen.update();
|
||||
},
|
||||
true,
|
||||
);
|
||||
|
@ -5,7 +5,6 @@
|
||||
import utils from './utils';
|
||||
import captions from './captions';
|
||||
import controls from './controls';
|
||||
import fullscreen from './fullscreen';
|
||||
import listeners from './listeners';
|
||||
|
||||
const ui = {
|
||||
@ -63,9 +62,6 @@ const ui = {
|
||||
// Remove native controls
|
||||
ui.toggleNativeControls.call(this);
|
||||
|
||||
// Setup fullscreen
|
||||
fullscreen.setup.call(this);
|
||||
|
||||
// Captions
|
||||
captions.setup.call(this);
|
||||
|
||||
|
@ -525,41 +525,46 @@ const utils = {
|
||||
},
|
||||
|
||||
// Trap focus inside container
|
||||
trapFocus() {
|
||||
trapFocus(element = null, toggle = false) {
|
||||
if (!utils.is.element(element)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const focusable = utils.getElements.call(this, 'button:not(:disabled), input:not(:disabled), [tabindex]');
|
||||
const first = focusable[0];
|
||||
const last = focusable[focusable.length - 1];
|
||||
|
||||
utils.on(
|
||||
this.elements.container,
|
||||
'keydown',
|
||||
event => {
|
||||
// Bail if not tab key or not fullscreen
|
||||
if (event.key !== 'Tab' || event.keyCode !== 9 || !this.fullscreen.active) {
|
||||
return;
|
||||
}
|
||||
const trap = event => {
|
||||
// Bail if not tab key or not fullscreen
|
||||
if (event.key !== 'Tab' || event.keyCode !== 9) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the current focused element
|
||||
const focused = utils.getFocusElement();
|
||||
// Get the current focused element
|
||||
const focused = utils.getFocusElement();
|
||||
|
||||
if (focused === last && !event.shiftKey) {
|
||||
// Move focus to first element that can be tabbed if Shift isn't used
|
||||
first.focus();
|
||||
event.preventDefault();
|
||||
} else if (focused === first && event.shiftKey) {
|
||||
// Move focus to last element that can be tabbed if Shift is used
|
||||
last.focus();
|
||||
event.preventDefault();
|
||||
}
|
||||
},
|
||||
false,
|
||||
);
|
||||
if (focused === last && !event.shiftKey) {
|
||||
// Move focus to first element that can be tabbed if Shift isn't used
|
||||
first.focus();
|
||||
event.preventDefault();
|
||||
} else if (focused === first && event.shiftKey) {
|
||||
// Move focus to last element that can be tabbed if Shift is used
|
||||
last.focus();
|
||||
event.preventDefault();
|
||||
}
|
||||
};
|
||||
|
||||
if (toggle) {
|
||||
utils.on(this.elements.container, 'keydown', trap, false);
|
||||
} else {
|
||||
utils.off(this.elements.container, 'keydown', trap, false);
|
||||
}
|
||||
},
|
||||
|
||||
// Toggle event listener
|
||||
toggleListener(elements, event, callback, toggle, passive, capture) {
|
||||
// Bail if no elements
|
||||
if (utils.is.nullOrUndefined(elements)) {
|
||||
// Bail if no elemetns, event, or callback
|
||||
if (utils.is.empty(elements) || utils.is.empty(event) || !utils.is.function(callback)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -3,9 +3,9 @@
|
||||
// --------------------------------------------------------------
|
||||
|
||||
.plyr__badge {
|
||||
background: $plyr-menu-color;
|
||||
background: $plyr-badge-bg;
|
||||
border-radius: 2px;
|
||||
color: $plyr-menu-bg;
|
||||
color: $plyr-badge-color;
|
||||
font-size: $plyr-font-size-badge;
|
||||
line-height: 1;
|
||||
padding: 3px 4px;
|
||||
|
@ -59,6 +59,14 @@
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
padding: $plyr-control-padding;
|
||||
|
||||
li {
|
||||
margin-top: 2px;
|
||||
|
||||
&:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Options
|
||||
|
@ -10,6 +10,7 @@
|
||||
@import 'settings/cosmetics';
|
||||
@import 'settings/type';
|
||||
|
||||
@import 'settings/badges';
|
||||
@import 'settings/captions';
|
||||
@import 'settings/controls';
|
||||
@import 'settings/helpers';
|
||||
|
6
src/sass/settings/badges.scss
Normal file
6
src/sass/settings/badges.scss
Normal file
@ -0,0 +1,6 @@
|
||||
// ==========================================================================
|
||||
// Badges
|
||||
// ==========================================================================
|
||||
|
||||
$plyr-badge-bg: $plyr-color-fiord !default;
|
||||
$plyr-badge-color: #fff !default;
|
Loading…
x
Reference in New Issue
Block a user