Merge branch 'develop' of github.com:sampotts/plyr into develop
# Conflicts: # src/js/captions.js # src/js/controls.js # src/js/fullscreen.js # src/js/html5.js # src/js/listeners.js # src/js/plugins/youtube.js # src/js/plyr.js # src/js/utils.js
This commit is contained in:
commit
aae1092bac
495
dist/plyr.js
vendored
495
dist/plyr.js
vendored
File diff suppressed because it is too large
Load Diff
2
dist/plyr.js.map
vendored
2
dist/plyr.js.map
vendored
File diff suppressed because one or more lines are too long
2
dist/plyr.min.js
vendored
2
dist/plyr.min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/plyr.min.js.map
vendored
2
dist/plyr.min.js.map
vendored
File diff suppressed because one or more lines are too long
521
dist/plyr.polyfilled.js
vendored
521
dist/plyr.polyfilled.js
vendored
File diff suppressed because it is too large
Load Diff
2
dist/plyr.polyfilled.js.map
vendored
2
dist/plyr.polyfilled.js.map
vendored
File diff suppressed because one or more lines are too long
2
dist/plyr.polyfilled.min.js
vendored
2
dist/plyr.polyfilled.min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/plyr.polyfilled.min.js.map
vendored
2
dist/plyr.polyfilled.min.js.map
vendored
File diff suppressed because one or more lines are too long
@ -215,7 +215,7 @@ You can specify a range of arguments for the constructor to use:
|
|||||||
|
|
||||||
* A CSS string selector that's compatible with [`querySelector`](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector)
|
* A CSS string selector that's compatible with [`querySelector`](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector)
|
||||||
* A [`HTMLElement`](https://developer.mozilla.org/en/docs/Web/API/HTMLElement)
|
* A [`HTMLElement`](https://developer.mozilla.org/en/docs/Web/API/HTMLElement)
|
||||||
* A [`NodeList]`(https://developer.mozilla.org/en-US/docs/Web/API/NodeList)
|
* A [`NodeList`](https://developer.mozilla.org/en-US/docs/Web/API/NodeList)
|
||||||
* A [jQuery](https://jquery.com) object
|
* A [jQuery](https://jquery.com) object
|
||||||
|
|
||||||
_Note_: If a `NodeList`, `Array`, or jQuery object are passed, the first element will be used for setup. To setup multiple players, see [setting up multiple players](#setting-up-multiple-players) below.
|
_Note_: If a `NodeList`, `Array`, or jQuery object are passed, the first element will be used for setup. To setup multiple players, see [setting up multiple players](#setting-up-multiple-players) below.
|
||||||
@ -367,6 +367,7 @@ player.fullscreen.enter(); // Enter fullscreen
|
|||||||
| `airplay()` | - | Trigger the airplay dialog on supported devices. |
|
| `airplay()` | - | Trigger the airplay dialog on supported devices. |
|
||||||
| `toggleControls(toggle)` | Boolean | Toggle the controls (video only). Takes optional truthy value to force it on/off. |
|
| `toggleControls(toggle)` | Boolean | Toggle the controls (video only). Takes optional truthy value to force it on/off. |
|
||||||
| `on(event, function)` | String, Function | Add an event listener for the specified event. |
|
| `on(event, function)` | String, Function | Add an event listener for the specified event. |
|
||||||
|
| `once(event, function)` | String, Function | Add an event listener for the specified event once. |
|
||||||
| `off(event, function)` | String, Function | Remove 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. |
|
| `supports(type)` | String | Check support for a mime type. |
|
||||||
| `destroy()` | - | Destroy the instance and garbage collect any elements. |
|
| `destroy()` | - | Destroy the instance and garbage collect any elements. |
|
||||||
|
@ -8,7 +8,7 @@ import i18n from './i18n';
|
|||||||
import support from './support';
|
import support from './support';
|
||||||
import browser from './utils/browser';
|
import browser from './utils/browser';
|
||||||
import { createElement, emptyElement, getAttributesFromSelector, insertAfter, removeElement, toggleClass } from './utils/elements';
|
import { createElement, emptyElement, getAttributesFromSelector, insertAfter, removeElement, toggleClass } from './utils/elements';
|
||||||
import { on, trigger } from './utils/events';
|
import { on, triggerEvent } from './utils/events';
|
||||||
import fetch from './utils/fetch';
|
import fetch from './utils/fetch';
|
||||||
import is from './utils/is';
|
import is from './utils/is';
|
||||||
import { getHTML } from './utils/strings';
|
import { getHTML } from './utils/strings';
|
||||||
@ -82,7 +82,7 @@ const captions = {
|
|||||||
// Watch changes to textTracks and update captions menu
|
// Watch changes to textTracks and update captions menu
|
||||||
if (this.isHTML5) {
|
if (this.isHTML5) {
|
||||||
const trackEvents = this.config.captions.update ? 'addtrack removetrack' : 'removetrack';
|
const trackEvents = this.config.captions.update ? 'addtrack removetrack' : 'removetrack';
|
||||||
on(this.media.textTracks, trackEvents, captions.update.bind(this));
|
on.call(this, this.media.textTracks, trackEvents, captions.update.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update available languages in list next tick (the event must not be triggered before the listeners)
|
// Update available languages in list next tick (the event must not be triggered before the listeners)
|
||||||
@ -107,7 +107,7 @@ const captions = {
|
|||||||
track.mode = 'hidden';
|
track.mode = 'hidden';
|
||||||
|
|
||||||
// Add event listener for cue changes
|
// Add event listener for cue changes
|
||||||
on(track, 'cuechange', () => captions.updateCues.call(this));
|
on.call(this, track, 'cuechange', () => captions.updateCues.call(this));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,7 +166,7 @@ const captions = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Trigger event
|
// Trigger event
|
||||||
trigger.call(this, this.media, 'languagechange');
|
triggerEvent.call(this, this.media, 'languagechange');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isHTML5 && this.isVideo) {
|
if (this.isHTML5 && this.isVideo) {
|
||||||
@ -280,7 +280,7 @@ const captions = {
|
|||||||
this.elements.captions.appendChild(caption);
|
this.elements.captions.appendChild(caption);
|
||||||
|
|
||||||
// Trigger event
|
// Trigger event
|
||||||
trigger.call(this, this.media, 'cuechange');
|
triggerEvent.call(this, this.media, 'cuechange');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
12
src/js/controls.js
vendored
12
src/js/controls.js
vendored
@ -7,9 +7,10 @@ import html5 from './html5';
|
|||||||
import i18n from './i18n';
|
import i18n from './i18n';
|
||||||
import support from './support';
|
import support from './support';
|
||||||
import { repaint, transitionEndEvent } from './utils/animation';
|
import { repaint, transitionEndEvent } from './utils/animation';
|
||||||
|
import { dedupe } from './utils/arrays';
|
||||||
import browser from './utils/browser';
|
import browser from './utils/browser';
|
||||||
import { createElement, emptyElement, getAttributesFromSelector, getElement, getElements, hasClass, removeElement, setAttributes, toggleClass, toggleHidden, toggleState } from './utils/elements';
|
import { createElement, emptyElement, getAttributesFromSelector, getElement, getElements, hasClass, removeElement, setAttributes, toggleClass, toggleHidden, toggleState } from './utils/elements';
|
||||||
import { off, on } from './utils/events';
|
import { once } from './utils/events';
|
||||||
import is from './utils/is';
|
import is from './utils/is';
|
||||||
import loadSprite from './utils/loadSprite';
|
import loadSprite from './utils/loadSprite';
|
||||||
import { extend } from './utils/objects';
|
import { extend } from './utils/objects';
|
||||||
@ -634,7 +635,6 @@ const controls = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// Set the quality menu
|
// Set the quality menu
|
||||||
// TODO: Vimeo support
|
|
||||||
setQualityMenu(options) {
|
setQualityMenu(options) {
|
||||||
// Menu required
|
// Menu required
|
||||||
if (!is.element(this.elements.settings.panes.quality)) {
|
if (!is.element(this.elements.settings.panes.quality)) {
|
||||||
@ -644,9 +644,9 @@ const controls = {
|
|||||||
const type = 'quality';
|
const type = 'quality';
|
||||||
const list = this.elements.settings.panes.quality.querySelector('ul');
|
const list = this.elements.settings.panes.quality.querySelector('ul');
|
||||||
|
|
||||||
// Set options if passed and filter based on config
|
// Set options if passed and filter based on uniqueness and config
|
||||||
if (is.array(options)) {
|
if (is.array(options)) {
|
||||||
this.options.quality = 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
|
// Toggle the pane and tab
|
||||||
@ -1065,12 +1065,10 @@ const controls = {
|
|||||||
container.style.width = '';
|
container.style.width = '';
|
||||||
container.style.height = '';
|
container.style.height = '';
|
||||||
|
|
||||||
// Only listen once
|
|
||||||
off(container, transitionEndEvent, restore);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Listen for the transition finishing and restore auto height/width
|
// Listen for the transition finishing and restore auto height/width
|
||||||
on(container, transitionEndEvent, restore);
|
once(container, transitionEndEvent, restore);
|
||||||
|
|
||||||
// Set dimensions to target
|
// Set dimensions to target
|
||||||
container.style.width = `${size.width}px`;
|
container.style.width = `${size.width}px`;
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
import browser from './utils/browser';
|
import browser from './utils/browser';
|
||||||
import { hasClass, toggleClass, toggleState, trapFocus } from './utils/elements';
|
import { hasClass, toggleClass, toggleState, trapFocus } from './utils/elements';
|
||||||
import { on, trigger } from './utils/events';
|
import { on, triggerEvent } from './utils/events';
|
||||||
import is from './utils/is';
|
import is from './utils/is';
|
||||||
|
|
||||||
function onChange() {
|
function onChange() {
|
||||||
@ -20,7 +20,7 @@ function onChange() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Trigger an event
|
// Trigger an event
|
||||||
trigger.call(this.player, this.target, this.active ? 'enterfullscreen' : 'exitfullscreen', true);
|
triggerEvent.call(this.player, this.target, this.active ? 'enterfullscreen' : 'exitfullscreen', true);
|
||||||
|
|
||||||
// Trap focus in container
|
// Trap focus in container
|
||||||
if (!browser.isIos) {
|
if (!browser.isIos) {
|
||||||
@ -63,13 +63,13 @@ class Fullscreen {
|
|||||||
|
|
||||||
// Register event listeners
|
// Register event listeners
|
||||||
// Handle event (incase user presses escape etc)
|
// Handle event (incase user presses escape etc)
|
||||||
on(document, this.prefix === 'ms' ? 'MSFullscreenChange' : `${this.prefix}fullscreenchange`, () => {
|
on.call(this.player, document, this.prefix === 'ms' ? 'MSFullscreenChange' : `${this.prefix}fullscreenchange`, () => {
|
||||||
// TODO: Filter for target??
|
// TODO: Filter for target??
|
||||||
onChange.call(this);
|
onChange.call(this);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Fullscreen toggle on double click
|
// Fullscreen toggle on double click
|
||||||
on(this.player.elements.container, 'dblclick', event => {
|
on.call(this.player, this.player.elements.container, 'dblclick', event => {
|
||||||
// Ignore double click in controls
|
// Ignore double click in controls
|
||||||
if (is.element(this.player.elements.controls) && this.player.elements.controls.contains(event.target)) {
|
if (is.element(this.player.elements.controls) && this.player.elements.controls.contains(event.target)) {
|
||||||
return;
|
return;
|
||||||
|
@ -3,43 +3,28 @@
|
|||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
import support from './support';
|
import support from './support';
|
||||||
import { dedupe } from './utils/arrays';
|
|
||||||
import { removeElement } from './utils/elements';
|
import { removeElement } from './utils/elements';
|
||||||
import { trigger } from './utils/events';
|
import { triggerEvent } from './utils/events';
|
||||||
import is from './utils/is';
|
|
||||||
|
|
||||||
const html5 = {
|
const html5 = {
|
||||||
getSources() {
|
getSources() {
|
||||||
if (!this.isHTML5) {
|
if (!this.isHTML5) {
|
||||||
return null;
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.media.querySelectorAll('source');
|
const sources = Array.from(this.media.querySelectorAll('source'));
|
||||||
|
|
||||||
|
// Filter out unsupported sources
|
||||||
|
return sources.filter(source => support.mime.call(this, source.getAttribute('type')));
|
||||||
},
|
},
|
||||||
|
|
||||||
// Get quality levels
|
// Get quality levels
|
||||||
getQualityOptions() {
|
getQualityOptions() {
|
||||||
if (!this.isHTML5) {
|
// Get sizes from <source> elements
|
||||||
return null;
|
return html5.getSources
|
||||||
}
|
.call(this)
|
||||||
|
.map(source => Number(source.getAttribute('size')))
|
||||||
// Get sources
|
.filter(Boolean);
|
||||||
const sources = html5.getSources.call(this);
|
|
||||||
|
|
||||||
if (is.empty(sources)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get <source> with size attribute
|
|
||||||
const sizes = Array.from(sources).filter(source => !is.empty(source.getAttribute('size')));
|
|
||||||
|
|
||||||
// If none, bail
|
|
||||||
if (is.empty(sizes)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reduce to unique list
|
|
||||||
return dedupe(sizes.map(source => Number(source.getAttribute('size'))));
|
|
||||||
},
|
},
|
||||||
|
|
||||||
extend() {
|
extend() {
|
||||||
@ -54,60 +39,34 @@ const html5 = {
|
|||||||
get() {
|
get() {
|
||||||
// Get sources
|
// Get sources
|
||||||
const sources = html5.getSources.call(player);
|
const sources = html5.getSources.call(player);
|
||||||
|
const [source] = sources.filter(source => source.getAttribute('src') === player.source);
|
||||||
|
|
||||||
if (is.empty(sources)) {
|
// Return size, if match is found
|
||||||
return null;
|
return source && Number(source.getAttribute('size'));
|
||||||
}
|
|
||||||
|
|
||||||
const matches = Array.from(sources).filter(source => source.getAttribute('src') === player.source);
|
|
||||||
|
|
||||||
if (is.empty(matches)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Number(matches[0].getAttribute('size'));
|
|
||||||
},
|
},
|
||||||
set(input) {
|
set(input) {
|
||||||
// Get sources
|
// Get sources
|
||||||
const sources = html5.getSources.call(player);
|
const sources = html5.getSources.call(player);
|
||||||
|
|
||||||
if (is.empty(sources)) {
|
// Get first match for requested size
|
||||||
|
const source = sources.find(source => Number(source.getAttribute('size')) === input);
|
||||||
|
|
||||||
|
// No matching source found
|
||||||
|
if (!source) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get matches for requested size
|
|
||||||
const matches = Array.from(sources).filter(source => Number(source.getAttribute('size')) === input);
|
|
||||||
|
|
||||||
// No matches for requested size
|
|
||||||
if (is.empty(matches)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get supported sources
|
|
||||||
const supported = matches.filter(source => support.mime.call(player, source.getAttribute('type')));
|
|
||||||
|
|
||||||
// No supported sources
|
|
||||||
if (is.empty(supported)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Trigger change event
|
|
||||||
trigger.call(player, player.media, 'qualityrequested', false, {
|
|
||||||
quality: input,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Get current state
|
// Get current state
|
||||||
const { currentTime, playing } = player;
|
const { currentTime, playing } = player;
|
||||||
|
|
||||||
// Set new source
|
// Set new source
|
||||||
player.media.src = supported[0].getAttribute('src');
|
player.media.src = source.getAttribute('src');
|
||||||
|
|
||||||
// Restore time
|
// Restore time
|
||||||
const onLoadedMetaData = () => {
|
const onLoadedMetaData = () => {
|
||||||
player.currentTime = currentTime;
|
player.currentTime = currentTime;
|
||||||
player.off('loadedmetadata', onLoadedMetaData);
|
|
||||||
};
|
};
|
||||||
player.on('loadedmetadata', onLoadedMetaData);
|
player.once('loadedmetadata', onLoadedMetaData);
|
||||||
|
|
||||||
// Load new source
|
// Load new source
|
||||||
player.media.load();
|
player.media.load();
|
||||||
@ -118,7 +77,7 @@ const html5 = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Trigger change event
|
// Trigger change event
|
||||||
trigger.call(player, player.media, 'qualitychange', false, {
|
triggerEvent.call(player, player.media, 'qualitychange', false, {
|
||||||
quality: input,
|
quality: input,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -133,7 +92,7 @@ const html5 = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove child sources
|
// Remove child sources
|
||||||
removeElement(html5.getSources());
|
removeElement(html5.getSources.call(this));
|
||||||
|
|
||||||
// Set blank video src attribute
|
// Set blank video src attribute
|
||||||
// This is to prevent a MEDIA_ERR_SRC_NOT_SUPPORTED error
|
// This is to prevent a MEDIA_ERR_SRC_NOT_SUPPORTED error
|
||||||
|
@ -6,7 +6,7 @@ import controls from './controls';
|
|||||||
import ui from './ui';
|
import ui from './ui';
|
||||||
import browser from './utils/browser';
|
import browser from './utils/browser';
|
||||||
import { getElement, getElements, getFocusElement, matches, toggleClass, toggleHidden } from './utils/elements';
|
import { getElement, getElements, getFocusElement, matches, toggleClass, toggleHidden } from './utils/elements';
|
||||||
import { off, on, toggleListener, trigger } from './utils/events';
|
import { on, once, toggleListener, triggerEvent } from './utils/events';
|
||||||
import is from './utils/is';
|
import is from './utils/is';
|
||||||
|
|
||||||
class Listeners {
|
class Listeners {
|
||||||
@ -197,39 +197,36 @@ class Listeners {
|
|||||||
// Add touch class
|
// Add touch class
|
||||||
toggleClass(this.player.elements.container, this.player.config.classNames.isTouch, true);
|
toggleClass(this.player.elements.container, this.player.config.classNames.isTouch, true);
|
||||||
|
|
||||||
// Clean up
|
|
||||||
off(document.body, 'touchstart', this.firstTouch);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Global window & document listeners
|
// Global window & document listeners
|
||||||
global(toggle = true) {
|
global(toggle = true) {
|
||||||
// Keyboard shortcuts
|
// Keyboard shortcuts
|
||||||
if (this.player.config.keyboard.global) {
|
if (this.player.config.keyboard.global) {
|
||||||
toggleListener(window, 'keydown keyup', this.handleKey, toggle, false);
|
toggleListener.call(this.player, window, 'keydown keyup', this.handleKey, toggle, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Click anywhere closes menu
|
// Click anywhere closes menu
|
||||||
toggleListener(document.body, 'click', this.toggleMenu, toggle);
|
toggleListener.call(this.player, document.body, 'click', this.toggleMenu, toggle);
|
||||||
|
|
||||||
// Detect touch by events
|
// Detect touch by events
|
||||||
on(document.body, 'touchstart', this.firstTouch);
|
once(document.body, 'touchstart', this.firstTouch);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Container listeners
|
// Container listeners
|
||||||
container() {
|
container() {
|
||||||
// Keyboard shortcuts
|
// Keyboard shortcuts
|
||||||
if (!this.player.config.keyboard.global && this.player.config.keyboard.focused) {
|
if (!this.player.config.keyboard.global && this.player.config.keyboard.focused) {
|
||||||
on(this.player.elements.container, 'keydown keyup', this.handleKey, false);
|
on.call(this.player, this.player.elements.container, 'keydown keyup', this.handleKey, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detect tab focus
|
// Detect tab focus
|
||||||
// Remove class on blur/focusout
|
// Remove class on blur/focusout
|
||||||
on(this.player.elements.container, 'focusout', event => {
|
on.call(this.player, this.player.elements.container, 'focusout', event => {
|
||||||
toggleClass(event.target, this.player.config.classNames.tabFocus, false);
|
toggleClass(event.target, this.player.config.classNames.tabFocus, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add classname to tabbed elements
|
// Add classname to tabbed elements
|
||||||
on(this.player.elements.container, 'keydown', event => {
|
on.call(this.player, this.player.elements.container, 'keydown', event => {
|
||||||
if (event.keyCode !== 9) {
|
if (event.keyCode !== 9) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -242,7 +239,7 @@ class Listeners {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Toggle controls on mouse events and entering fullscreen
|
// Toggle controls on mouse events and entering fullscreen
|
||||||
on(this.player.elements.container, 'mousemove mouseleave touchstart touchmove enterfullscreen exitfullscreen', event => {
|
on.call(this.player, this.player.elements.container, 'mousemove mouseleave touchstart touchmove enterfullscreen exitfullscreen', event => {
|
||||||
const { controls } = this.player.elements;
|
const { controls } = this.player.elements;
|
||||||
|
|
||||||
// Remove button states for fullscreen
|
// Remove button states for fullscreen
|
||||||
@ -276,20 +273,20 @@ class Listeners {
|
|||||||
// Listen for media events
|
// Listen for media events
|
||||||
media() {
|
media() {
|
||||||
// Time change on media
|
// Time change on media
|
||||||
on(this.player.media, 'timeupdate seeking seeked', event => controls.timeUpdate.call(this.player, event));
|
on.call(this.player, this.player.media, 'timeupdate seeking seeked', event => controls.timeUpdate.call(this.player, event));
|
||||||
|
|
||||||
// Display duration
|
// Display duration
|
||||||
on(this.player.media, 'durationchange loadeddata loadedmetadata', event => controls.durationUpdate.call(this.player, event));
|
on.call(this.player, this.player.media, 'durationchange loadeddata loadedmetadata', event => controls.durationUpdate.call(this.player, event));
|
||||||
|
|
||||||
// Check for audio tracks on load
|
// Check for audio tracks on load
|
||||||
// We can't use `loadedmetadata` as it doesn't seem to have audio tracks at that point
|
// We can't use `loadedmetadata` as it doesn't seem to have audio tracks at that point
|
||||||
on(this.player.media, 'loadeddata canplay', () => {
|
on.call(this.player, this.player.media, 'canplay', () => {
|
||||||
toggleHidden(this.player.elements.volume, !this.player.hasAudio);
|
toggleHidden(this.player.elements.volume, !this.player.hasAudio);
|
||||||
toggleHidden(this.player.elements.buttons.mute, !this.player.hasAudio);
|
toggleHidden(this.player.elements.buttons.mute, !this.player.hasAudio);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle the media finishing
|
// Handle the media finishing
|
||||||
on(this.player.media, 'ended', () => {
|
on.call(this.player, this.player.media, 'ended', () => {
|
||||||
// Show poster on end
|
// Show poster on end
|
||||||
if (this.player.isHTML5 && this.player.isVideo && this.player.config.resetOnEnd) {
|
if (this.player.isHTML5 && this.player.isVideo && this.player.config.resetOnEnd) {
|
||||||
// Restart
|
// Restart
|
||||||
@ -298,20 +295,20 @@ class Listeners {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Check for buffer progress
|
// Check for buffer progress
|
||||||
on(this.player.media, 'progress playing seeking seeked', event => controls.updateProgress.call(this.player, event));
|
on.call(this.player, this.player.media, 'progress playing seeking seeked', event => controls.updateProgress.call(this.player, event));
|
||||||
|
|
||||||
// Handle volume changes
|
// Handle volume changes
|
||||||
on(this.player.media, 'volumechange', event => controls.updateVolume.call(this.player, event));
|
on.call(this.player, this.player.media, 'volumechange', event => controls.updateVolume.call(this.player, event));
|
||||||
|
|
||||||
// Handle play/pause
|
// Handle play/pause
|
||||||
on(this.player.media, 'playing play pause ended emptied timeupdate', event => ui.checkPlaying.call(this.player, event));
|
on.call(this.player, this.player.media, 'playing play pause ended emptied timeupdate', event => ui.checkPlaying.call(this.player, event));
|
||||||
|
|
||||||
// Loading state
|
// Loading state
|
||||||
on(this.player.media, 'waiting canplay seeked playing', event => ui.checkLoading.call(this.player, event));
|
on.call(this.player, this.player.media, 'waiting canplay seeked playing', event => ui.checkLoading.call(this.player, event));
|
||||||
|
|
||||||
// If autoplay, then load advertisement if required
|
// If autoplay, then load advertisement if required
|
||||||
// TODO: Show some sort of loading state while the ad manager loads else there's a delay before ad shows
|
// TODO: Show some sort of loading state while the ad manager loads else there's a delay before ad shows
|
||||||
on(this.player.media, 'playing', () => {
|
on.call(this.player, this.player.media, 'playing', () => {
|
||||||
if (!this.player.ads) {
|
if (!this.player.ads) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -334,7 +331,7 @@ class Listeners {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// On click play, pause ore restart
|
// On click play, pause ore restart
|
||||||
on(wrapper, 'click', () => {
|
on.call(this.player, wrapper, 'click', () => {
|
||||||
// Touch devices will just show controls (if we're hiding controls)
|
// Touch devices will just show controls (if we're hiding controls)
|
||||||
if (this.player.config.hideControls && this.player.touch && !this.player.paused) {
|
if (this.player.config.hideControls && this.player.touch && !this.player.paused) {
|
||||||
return;
|
return;
|
||||||
@ -353,7 +350,7 @@ class Listeners {
|
|||||||
|
|
||||||
// Disable right click
|
// Disable right click
|
||||||
if (this.player.supported.ui && this.player.config.disableContextMenu) {
|
if (this.player.supported.ui && this.player.config.disableContextMenu) {
|
||||||
on(
|
on.call(this.player,
|
||||||
this.player.elements.wrapper,
|
this.player.elements.wrapper,
|
||||||
'contextmenu',
|
'contextmenu',
|
||||||
event => {
|
event => {
|
||||||
@ -364,13 +361,13 @@ class Listeners {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Volume change
|
// Volume change
|
||||||
on(this.player.media, 'volumechange', () => {
|
on.call(this.player, this.player.media, 'volumechange', () => {
|
||||||
// Save to storage
|
// Save to storage
|
||||||
this.player.storage.set({ volume: this.player.volume, muted: this.player.muted });
|
this.player.storage.set({ volume: this.player.volume, muted: this.player.muted });
|
||||||
});
|
});
|
||||||
|
|
||||||
// Speed change
|
// Speed change
|
||||||
on(this.player.media, 'ratechange', () => {
|
on.call(this.player, this.player.media, 'ratechange', () => {
|
||||||
// Update UI
|
// Update UI
|
||||||
controls.updateSetting.call(this.player, 'speed');
|
controls.updateSetting.call(this.player, 'speed');
|
||||||
|
|
||||||
@ -379,19 +376,19 @@ class Listeners {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Quality request
|
// Quality request
|
||||||
on(this.player.media, 'qualityrequested', event => {
|
on.call(this.player, this.player.media, 'qualityrequested', event => {
|
||||||
// Save to storage
|
// Save to storage
|
||||||
this.player.storage.set({ quality: event.detail.quality });
|
this.player.storage.set({ quality: event.detail.quality });
|
||||||
});
|
});
|
||||||
|
|
||||||
// Quality change
|
// Quality change
|
||||||
on(this.player.media, 'qualitychange', event => {
|
on.call(this.player, this.player.media, 'qualitychange', event => {
|
||||||
// Update UI
|
// Update UI
|
||||||
controls.updateSetting.call(this.player, 'quality', null, event.detail.quality);
|
controls.updateSetting.call(this.player, 'quality', null, event.detail.quality);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Caption language change
|
// Caption language change
|
||||||
on(this.player.media, 'languagechange', () => {
|
on.call(this.player, this.player.media, 'languagechange', () => {
|
||||||
// Update UI
|
// Update UI
|
||||||
controls.updateSetting.call(this.player, 'captions');
|
controls.updateSetting.call(this.player, 'captions');
|
||||||
|
|
||||||
@ -400,7 +397,7 @@ class Listeners {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Captions toggle
|
// Captions toggle
|
||||||
on(this.player.media, 'captionsenabled captionsdisabled', () => {
|
on.call(this.player, this.player.media, 'captionsenabled captionsdisabled', () => {
|
||||||
// Update UI
|
// Update UI
|
||||||
controls.updateSetting.call(this.player, 'captions');
|
controls.updateSetting.call(this.player, 'captions');
|
||||||
|
|
||||||
@ -410,7 +407,7 @@ class Listeners {
|
|||||||
|
|
||||||
// Proxy events to container
|
// Proxy events to container
|
||||||
// Bubble up key events for Edge
|
// Bubble up key events for Edge
|
||||||
on(this.player.media, this.player.config.events.concat([
|
on.call(this.player, this.player.media, this.player.config.events.concat([
|
||||||
'keyup',
|
'keyup',
|
||||||
'keydown',
|
'keydown',
|
||||||
]).join(' '), event => {
|
]).join(' '), event => {
|
||||||
@ -421,7 +418,7 @@ class Listeners {
|
|||||||
detail = this.player.media.error;
|
detail = this.player.media.error;
|
||||||
}
|
}
|
||||||
|
|
||||||
trigger.call(this.player, this.player.elements.container, event.type, true, detail);
|
triggerEvent.call(this.player, this.player.elements.container, event.type, true, detail);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -452,7 +449,7 @@ class Listeners {
|
|||||||
const customHandler = this.player.config.listeners[customHandlerKey];
|
const customHandler = this.player.config.listeners[customHandlerKey];
|
||||||
const hasCustomHandler = is.function(customHandler);
|
const hasCustomHandler = is.function(customHandler);
|
||||||
|
|
||||||
on(element, type, event => proxy(event, defaultHandler, customHandlerKey), passive && !hasCustomHandler);
|
on.call(this.player, element, type, event => proxy(event, defaultHandler, customHandlerKey), passive && !hasCustomHandler);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Play/pause toggle
|
// Play/pause toggle
|
||||||
@ -727,11 +724,6 @@ class Listeners {
|
|||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset on destroy
|
|
||||||
clear() {
|
|
||||||
this.global(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Listeners;
|
export default Listeners;
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
import i18n from '../i18n';
|
import i18n from '../i18n';
|
||||||
import { createElement } from './../utils/elements';
|
import { createElement } from './../utils/elements';
|
||||||
import { trigger } from './../utils/events';
|
import { triggerEvent } from './../utils/events';
|
||||||
import is from './../utils/is';
|
import is from './../utils/is';
|
||||||
import loadScript from './../utils/loadScript';
|
import loadScript from './../utils/loadScript';
|
||||||
import { formatTime } from './../utils/time';
|
import { formatTime } from './../utils/time';
|
||||||
@ -270,7 +270,7 @@ class Ads {
|
|||||||
// Proxy event
|
// Proxy event
|
||||||
const dispatchEvent = type => {
|
const dispatchEvent = type => {
|
||||||
const event = `ads${type.replace(/_/g, '').toLowerCase()}`;
|
const event = `ads${type.replace(/_/g, '').toLowerCase()}`;
|
||||||
trigger.call(this.player, this.player.media, event);
|
triggerEvent.call(this.player, this.player.media, event);
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
|
@ -6,7 +6,7 @@ import captions from './../captions';
|
|||||||
import controls from './../controls';
|
import controls from './../controls';
|
||||||
import ui from './../ui';
|
import ui from './../ui';
|
||||||
import { createElement, replaceElement, toggleClass } from './../utils/elements';
|
import { createElement, replaceElement, toggleClass } from './../utils/elements';
|
||||||
import { trigger } from './../utils/events';
|
import { triggerEvent } from './../utils/events';
|
||||||
import fetch from './../utils/fetch';
|
import fetch from './../utils/fetch';
|
||||||
import is from './../utils/is';
|
import is from './../utils/is';
|
||||||
import loadScript from './../utils/loadScript';
|
import loadScript from './../utils/loadScript';
|
||||||
@ -41,7 +41,7 @@ function assurePlaybackState(play) {
|
|||||||
}
|
}
|
||||||
if (this.media.paused === play) {
|
if (this.media.paused === play) {
|
||||||
this.media.paused = !play;
|
this.media.paused = !play;
|
||||||
trigger.call(this, this.media, play ? 'play' : 'pause');
|
triggerEvent.call(this, this.media, play ? 'play' : 'pause');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,7 +186,7 @@ const vimeo = {
|
|||||||
|
|
||||||
// Set seeking state and trigger event
|
// Set seeking state and trigger event
|
||||||
media.seeking = true;
|
media.seeking = true;
|
||||||
trigger.call(player, media, 'seeking');
|
triggerEvent.call(player, media, 'seeking');
|
||||||
|
|
||||||
// If paused, mute until seek is complete
|
// If paused, mute until seek is complete
|
||||||
Promise.resolve(restorePause && embed.setVolume(0))
|
Promise.resolve(restorePause && embed.setVolume(0))
|
||||||
@ -213,7 +213,7 @@ const vimeo = {
|
|||||||
.setPlaybackRate(input)
|
.setPlaybackRate(input)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
speed = input;
|
speed = input;
|
||||||
trigger.call(player, player.media, 'ratechange');
|
triggerEvent.call(player, player.media, 'ratechange');
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
// Hide menu item (and menu if empty)
|
// Hide menu item (and menu if empty)
|
||||||
@ -233,7 +233,7 @@ const vimeo = {
|
|||||||
set(input) {
|
set(input) {
|
||||||
player.embed.setVolume(input).then(() => {
|
player.embed.setVolume(input).then(() => {
|
||||||
volume = input;
|
volume = input;
|
||||||
trigger.call(player, player.media, 'volumechange');
|
triggerEvent.call(player, player.media, 'volumechange');
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -249,7 +249,7 @@ const vimeo = {
|
|||||||
|
|
||||||
player.embed.setVolume(toggle ? 0 : player.config.volume).then(() => {
|
player.embed.setVolume(toggle ? 0 : player.config.volume).then(() => {
|
||||||
muted = toggle;
|
muted = toggle;
|
||||||
trigger.call(player, player.media, 'volumechange');
|
triggerEvent.call(player, player.media, 'volumechange');
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -316,13 +316,13 @@ const vimeo = {
|
|||||||
// Get current time
|
// Get current time
|
||||||
player.embed.getCurrentTime().then(value => {
|
player.embed.getCurrentTime().then(value => {
|
||||||
currentTime = value;
|
currentTime = value;
|
||||||
trigger.call(player, player.media, 'timeupdate');
|
triggerEvent.call(player, player.media, 'timeupdate');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Get duration
|
// Get duration
|
||||||
player.embed.getDuration().then(value => {
|
player.embed.getDuration().then(value => {
|
||||||
player.media.duration = value;
|
player.media.duration = value;
|
||||||
trigger.call(player, player.media, 'durationchange');
|
triggerEvent.call(player, player.media, 'durationchange');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Get captions
|
// Get captions
|
||||||
@ -341,7 +341,7 @@ const vimeo = {
|
|||||||
player.embed.getPaused().then(paused => {
|
player.embed.getPaused().then(paused => {
|
||||||
assurePlaybackState.call(player, !paused);
|
assurePlaybackState.call(player, !paused);
|
||||||
if (!paused) {
|
if (!paused) {
|
||||||
trigger.call(player, player.media, 'playing');
|
triggerEvent.call(player, player.media, 'playing');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -356,7 +356,7 @@ const vimeo = {
|
|||||||
|
|
||||||
player.embed.on('play', () => {
|
player.embed.on('play', () => {
|
||||||
assurePlaybackState.call(player, true);
|
assurePlaybackState.call(player, true);
|
||||||
trigger.call(player, player.media, 'playing');
|
triggerEvent.call(player, player.media, 'playing');
|
||||||
});
|
});
|
||||||
|
|
||||||
player.embed.on('pause', () => {
|
player.embed.on('pause', () => {
|
||||||
@ -366,16 +366,16 @@ const vimeo = {
|
|||||||
player.embed.on('timeupdate', data => {
|
player.embed.on('timeupdate', data => {
|
||||||
player.media.seeking = false;
|
player.media.seeking = false;
|
||||||
currentTime = data.seconds;
|
currentTime = data.seconds;
|
||||||
trigger.call(player, player.media, 'timeupdate');
|
triggerEvent.call(player, player.media, 'timeupdate');
|
||||||
});
|
});
|
||||||
|
|
||||||
player.embed.on('progress', data => {
|
player.embed.on('progress', data => {
|
||||||
player.media.buffered = data.percent;
|
player.media.buffered = data.percent;
|
||||||
trigger.call(player, player.media, 'progress');
|
triggerEvent.call(player, player.media, 'progress');
|
||||||
|
|
||||||
// Check all loaded
|
// Check all loaded
|
||||||
if (parseInt(data.percent, 10) === 1) {
|
if (parseInt(data.percent, 10) === 1) {
|
||||||
trigger.call(player, player.media, 'canplaythrough');
|
triggerEvent.call(player, player.media, 'canplaythrough');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get duration as if we do it before load, it gives an incorrect value
|
// Get duration as if we do it before load, it gives an incorrect value
|
||||||
@ -383,24 +383,24 @@ const vimeo = {
|
|||||||
player.embed.getDuration().then(value => {
|
player.embed.getDuration().then(value => {
|
||||||
if (value !== player.media.duration) {
|
if (value !== player.media.duration) {
|
||||||
player.media.duration = value;
|
player.media.duration = value;
|
||||||
trigger.call(player, player.media, 'durationchange');
|
triggerEvent.call(player, player.media, 'durationchange');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
player.embed.on('seeked', () => {
|
player.embed.on('seeked', () => {
|
||||||
player.media.seeking = false;
|
player.media.seeking = false;
|
||||||
trigger.call(player, player.media, 'seeked');
|
triggerEvent.call(player, player.media, 'seeked');
|
||||||
});
|
});
|
||||||
|
|
||||||
player.embed.on('ended', () => {
|
player.embed.on('ended', () => {
|
||||||
player.media.paused = true;
|
player.media.paused = true;
|
||||||
trigger.call(player, player.media, 'ended');
|
triggerEvent.call(player, player.media, 'ended');
|
||||||
});
|
});
|
||||||
|
|
||||||
player.embed.on('error', detail => {
|
player.embed.on('error', detail => {
|
||||||
player.media.error = detail;
|
player.media.error = detail;
|
||||||
trigger.call(player, player.media, 'error');
|
triggerEvent.call(player, player.media, 'error');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Rebuild UI
|
// Rebuild UI
|
||||||
|
@ -6,7 +6,7 @@ import controls from './../controls';
|
|||||||
import ui from './../ui';
|
import ui from './../ui';
|
||||||
import { dedupe } from './../utils/arrays';
|
import { dedupe } from './../utils/arrays';
|
||||||
import { createElement, replaceElement, toggleClass } from './../utils/elements';
|
import { createElement, replaceElement, toggleClass } from './../utils/elements';
|
||||||
import { trigger } from './../utils/events';
|
import { triggerEvent } from './../utils/events';
|
||||||
import fetch from './../utils/fetch';
|
import fetch from './../utils/fetch';
|
||||||
import is from './../utils/is';
|
import is from './../utils/is';
|
||||||
import loadImage from './../utils/loadImage';
|
import loadImage from './../utils/loadImage';
|
||||||
@ -25,52 +25,25 @@ function parseId(url) {
|
|||||||
|
|
||||||
// Standardise YouTube quality unit
|
// Standardise YouTube quality unit
|
||||||
function mapQualityUnit(input) {
|
function mapQualityUnit(input) {
|
||||||
switch (input) {
|
const qualities = {
|
||||||
case 'hd2160':
|
hd2160: 2160,
|
||||||
return 2160;
|
hd1440: 1440,
|
||||||
|
hd1080: 1080,
|
||||||
|
hd720: 720,
|
||||||
|
large: 480,
|
||||||
|
medium: 360,
|
||||||
|
small: 240,
|
||||||
|
tiny: 144,
|
||||||
|
};
|
||||||
|
|
||||||
case 2160:
|
const entry = Object.entries(qualities).find(entry => entry.includes(input));
|
||||||
return 'hd2160';
|
|
||||||
|
|
||||||
case 'hd1440':
|
if (entry) {
|
||||||
return 1440;
|
// Get the match corresponding to the input
|
||||||
|
return entry.find(value => value !== input);
|
||||||
case 1440:
|
|
||||||
return 'hd1440';
|
|
||||||
|
|
||||||
case 'hd1080':
|
|
||||||
return 1080;
|
|
||||||
|
|
||||||
case 1080:
|
|
||||||
return 'hd1080';
|
|
||||||
|
|
||||||
case 'hd720':
|
|
||||||
return 720;
|
|
||||||
|
|
||||||
case 720:
|
|
||||||
return 'hd720';
|
|
||||||
|
|
||||||
case 'large':
|
|
||||||
return 480;
|
|
||||||
|
|
||||||
case 480:
|
|
||||||
return 'large';
|
|
||||||
|
|
||||||
case 'medium':
|
|
||||||
return 360;
|
|
||||||
|
|
||||||
case 360:
|
|
||||||
return 'medium';
|
|
||||||
|
|
||||||
case 'small':
|
|
||||||
return 240;
|
|
||||||
|
|
||||||
case 240:
|
|
||||||
return 'small';
|
|
||||||
|
|
||||||
default:
|
|
||||||
return 'default';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 'default';
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapQualityUnits(levels) {
|
function mapQualityUnits(levels) {
|
||||||
@ -88,7 +61,7 @@ function assurePlaybackState(play) {
|
|||||||
}
|
}
|
||||||
if (this.media.paused === play) {
|
if (this.media.paused === play) {
|
||||||
this.media.paused = !play;
|
this.media.paused = !play;
|
||||||
trigger.call(this, this.media, play ? 'play' : 'pause');
|
triggerEvent.call(this, this.media, play ? 'play' : 'pause');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,10 +239,10 @@ const youtube = {
|
|||||||
|
|
||||||
player.media.error = detail;
|
player.media.error = detail;
|
||||||
|
|
||||||
trigger.call(player, player.media, 'error');
|
triggerEvent.call(player, player.media, 'error');
|
||||||
},
|
},
|
||||||
onPlaybackQualityChange() {
|
onPlaybackQualityChange() {
|
||||||
trigger.call(player, player.media, 'qualitychange', false, {
|
triggerEvent.call(player, player.media, 'qualitychange', false, {
|
||||||
quality: player.media.quality,
|
quality: player.media.quality,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -280,7 +253,7 @@ const youtube = {
|
|||||||
// Get current speed
|
// Get current speed
|
||||||
player.media.playbackRate = instance.getPlaybackRate();
|
player.media.playbackRate = instance.getPlaybackRate();
|
||||||
|
|
||||||
trigger.call(player, player.media, 'ratechange');
|
triggerEvent.call(player, player.media, 'ratechange');
|
||||||
},
|
},
|
||||||
onReady(event) {
|
onReady(event) {
|
||||||
// Get the instance
|
// Get the instance
|
||||||
@ -321,7 +294,7 @@ const youtube = {
|
|||||||
|
|
||||||
// Set seeking state and trigger event
|
// Set seeking state and trigger event
|
||||||
player.media.seeking = true;
|
player.media.seeking = true;
|
||||||
trigger.call(player, player.media, 'seeking');
|
triggerEvent.call(player, player.media, 'seeking');
|
||||||
|
|
||||||
// Seek after events sent
|
// Seek after events sent
|
||||||
instance.seekTo(time);
|
instance.seekTo(time);
|
||||||
@ -344,15 +317,7 @@ const youtube = {
|
|||||||
return mapQualityUnit(instance.getPlaybackQuality());
|
return mapQualityUnit(instance.getPlaybackQuality());
|
||||||
},
|
},
|
||||||
set(input) {
|
set(input) {
|
||||||
const quality = input;
|
instance.setPlaybackQuality(mapQualityUnit(input));
|
||||||
|
|
||||||
// Set via API
|
|
||||||
instance.setPlaybackQuality(mapQualityUnit(quality));
|
|
||||||
|
|
||||||
// Trigger request event
|
|
||||||
trigger.call(player, player.media, 'qualityrequested', false, {
|
|
||||||
quality,
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -365,7 +330,7 @@ const youtube = {
|
|||||||
set(input) {
|
set(input) {
|
||||||
volume = input;
|
volume = input;
|
||||||
instance.setVolume(volume * 100);
|
instance.setVolume(volume * 100);
|
||||||
trigger.call(player, player.media, 'volumechange');
|
triggerEvent.call(player, player.media, 'volumechange');
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -379,7 +344,7 @@ const youtube = {
|
|||||||
const toggle = is.boolean(input) ? input : muted;
|
const toggle = is.boolean(input) ? input : muted;
|
||||||
muted = toggle;
|
muted = toggle;
|
||||||
instance[toggle ? 'mute' : 'unMute']();
|
instance[toggle ? 'mute' : 'unMute']();
|
||||||
trigger.call(player, player.media, 'volumechange');
|
triggerEvent.call(player, player.media, 'volumechange');
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -405,8 +370,8 @@ const youtube = {
|
|||||||
player.media.setAttribute('tabindex', -1);
|
player.media.setAttribute('tabindex', -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
trigger.call(player, player.media, 'timeupdate');
|
triggerEvent.call(player, player.media, 'timeupdate');
|
||||||
trigger.call(player, player.media, 'durationchange');
|
triggerEvent.call(player, player.media, 'durationchange');
|
||||||
|
|
||||||
// Reset timer
|
// Reset timer
|
||||||
clearInterval(player.timers.buffering);
|
clearInterval(player.timers.buffering);
|
||||||
@ -418,7 +383,7 @@ const youtube = {
|
|||||||
|
|
||||||
// Trigger progress only when we actually buffer something
|
// Trigger progress only when we actually buffer something
|
||||||
if (player.media.lastBuffered === null || player.media.lastBuffered < player.media.buffered) {
|
if (player.media.lastBuffered === null || player.media.lastBuffered < player.media.buffered) {
|
||||||
trigger.call(player, player.media, 'progress');
|
triggerEvent.call(player, player.media, 'progress');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set last buffer point
|
// Set last buffer point
|
||||||
@ -429,7 +394,7 @@ const youtube = {
|
|||||||
clearInterval(player.timers.buffering);
|
clearInterval(player.timers.buffering);
|
||||||
|
|
||||||
// Trigger event
|
// Trigger event
|
||||||
trigger.call(player, player.media, 'canplaythrough');
|
triggerEvent.call(player, player.media, 'canplaythrough');
|
||||||
}
|
}
|
||||||
}, 200);
|
}, 200);
|
||||||
|
|
||||||
@ -451,7 +416,7 @@ const youtube = {
|
|||||||
if (seeked) {
|
if (seeked) {
|
||||||
// Unset seeking and fire seeked event
|
// Unset seeking and fire seeked event
|
||||||
player.media.seeking = false;
|
player.media.seeking = false;
|
||||||
trigger.call(player, player.media, 'seeked');
|
triggerEvent.call(player, player.media, 'seeked');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle events
|
// Handle events
|
||||||
@ -464,11 +429,11 @@ const youtube = {
|
|||||||
switch (event.data) {
|
switch (event.data) {
|
||||||
case -1:
|
case -1:
|
||||||
// Update scrubber
|
// Update scrubber
|
||||||
trigger.call(player, player.media, 'timeupdate');
|
triggerEvent.call(player, player.media, 'timeupdate');
|
||||||
|
|
||||||
// Get loaded % from YouTube
|
// Get loaded % from YouTube
|
||||||
player.media.buffered = instance.getVideoLoadedFraction();
|
player.media.buffered = instance.getVideoLoadedFraction();
|
||||||
trigger.call(player, player.media, 'progress');
|
triggerEvent.call(player, player.media, 'progress');
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -481,7 +446,7 @@ const youtube = {
|
|||||||
instance.stopVideo();
|
instance.stopVideo();
|
||||||
instance.playVideo();
|
instance.playVideo();
|
||||||
} else {
|
} else {
|
||||||
trigger.call(player, player.media, 'ended');
|
triggerEvent.call(player, player.media, 'ended');
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -493,11 +458,11 @@ const youtube = {
|
|||||||
} else {
|
} else {
|
||||||
assurePlaybackState.call(player, true);
|
assurePlaybackState.call(player, true);
|
||||||
|
|
||||||
trigger.call(player, player.media, 'playing');
|
triggerEvent.call(player, player.media, 'playing');
|
||||||
|
|
||||||
// Poll to get playback progress
|
// Poll to get playback progress
|
||||||
player.timers.playing = setInterval(() => {
|
player.timers.playing = setInterval(() => {
|
||||||
trigger.call(player, player.media, 'timeupdate');
|
triggerEvent.call(player, player.media, 'timeupdate');
|
||||||
}, 50);
|
}, 50);
|
||||||
|
|
||||||
// Check duration again due to YouTube bug
|
// Check duration again due to YouTube bug
|
||||||
@ -505,7 +470,7 @@ const youtube = {
|
|||||||
// https://code.google.com/p/gdata-issues/issues/detail?id=8690
|
// https://code.google.com/p/gdata-issues/issues/detail?id=8690
|
||||||
if (player.media.duration !== instance.getDuration()) {
|
if (player.media.duration !== instance.getDuration()) {
|
||||||
player.media.duration = instance.getDuration();
|
player.media.duration = instance.getDuration();
|
||||||
trigger.call(player, player.media, 'durationchange');
|
triggerEvent.call(player, player.media, 'durationchange');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get quality
|
// Get quality
|
||||||
@ -527,7 +492,7 @@ const youtube = {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
trigger.call(player, player.elements.container, 'statechange', false, {
|
triggerEvent.call(player, player.elements.container, 'statechange', false, {
|
||||||
code: event.data,
|
code: event.data,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -20,9 +20,9 @@ import support from './support';
|
|||||||
import ui from './ui';
|
import ui from './ui';
|
||||||
import { closest } from './utils/arrays';
|
import { closest } from './utils/arrays';
|
||||||
import { createElement, hasClass, removeElement, replaceElement, toggleClass, toggleState, wrap } from './utils/elements';
|
import { createElement, hasClass, removeElement, replaceElement, toggleClass, toggleState, wrap } from './utils/elements';
|
||||||
import { off, on, trigger } from './utils/events';
|
import { off, on, once, triggerEvent, unbindListeners } from './utils/events';
|
||||||
import is from './utils/is';
|
import is from './utils/is';
|
||||||
import loadSprite from './utils/loadScript';
|
import loadSprite from './utils/loadSprite';
|
||||||
import { cloneDeep, extend } from './utils/objects';
|
import { cloneDeep, extend } from './utils/objects';
|
||||||
import { parseUrl } from './utils/urls';
|
import { parseUrl } from './utils/urls';
|
||||||
|
|
||||||
@ -171,7 +171,7 @@ class Plyr {
|
|||||||
this.elements.container.className = '';
|
this.elements.container.className = '';
|
||||||
|
|
||||||
// Get attributes from URL and set config
|
// Get attributes from URL and set config
|
||||||
if (!url.searchParams) {
|
if (url.searchParams.length) {
|
||||||
const truthy = [
|
const truthy = [
|
||||||
'1',
|
'1',
|
||||||
'true',
|
'true',
|
||||||
@ -249,6 +249,8 @@ class Plyr {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.eventListeners = [];
|
||||||
|
|
||||||
// Create listeners
|
// Create listeners
|
||||||
this.listeners = new Listeners(this);
|
this.listeners = new Listeners(this);
|
||||||
|
|
||||||
@ -275,7 +277,7 @@ class Plyr {
|
|||||||
|
|
||||||
// Listen for events if debugging
|
// Listen for events if debugging
|
||||||
if (this.config.debug) {
|
if (this.config.debug) {
|
||||||
on(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}`);
|
this.debug.log(`event: ${event.type}`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -673,36 +675,31 @@ class Plyr {
|
|||||||
* @param {number} input - Quality level
|
* @param {number} input - Quality level
|
||||||
*/
|
*/
|
||||||
set quality(input) {
|
set quality(input) {
|
||||||
let quality = null;
|
const config = this.config.quality;
|
||||||
|
const options = this.options.quality;
|
||||||
|
|
||||||
if (!is.empty(input)) {
|
if (!options.length) {
|
||||||
quality = Number(input);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is.number(quality)) {
|
|
||||||
quality = this.storage.get('quality');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is.number(quality)) {
|
|
||||||
quality = this.config.quality.selected;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is.number(quality)) {
|
|
||||||
quality = this.config.quality.default;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.options.quality.length) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.options.quality.includes(quality)) {
|
let quality = ([
|
||||||
const value = closest(this.options.quality, quality);
|
!is.empty(input) && Number(input),
|
||||||
|
this.storage.get('quality'),
|
||||||
|
config.selected,
|
||||||
|
config.default,
|
||||||
|
]).find(is.number);
|
||||||
|
|
||||||
|
if (!options.includes(quality)) {
|
||||||
|
const value = closest(options, quality);
|
||||||
this.debug.warn(`Unsupported quality option: ${quality}, using ${value} instead`);
|
this.debug.warn(`Unsupported quality option: ${quality}, using ${value} instead`);
|
||||||
quality = value;
|
quality = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Trigger request event
|
||||||
|
triggerEvent.call(this, this.media, 'qualityrequested', false, { quality });
|
||||||
|
|
||||||
// Update config
|
// Update config
|
||||||
this.config.quality.selected = quality;
|
config.selected = quality;
|
||||||
|
|
||||||
// Set quality
|
// Set quality
|
||||||
this.media.quality = quality;
|
this.media.quality = quality;
|
||||||
@ -853,7 +850,7 @@ class Plyr {
|
|||||||
// Update state and trigger event
|
// Update state and trigger event
|
||||||
if (active !== this.captions.active) {
|
if (active !== this.captions.active) {
|
||||||
this.captions.active = active;
|
this.captions.active = active;
|
||||||
trigger.call(this, this.media, this.captions.active ? 'captionsenabled' : 'captionsdisabled');
|
triggerEvent.call(this, this.media, this.captions.active ? 'captionsenabled' : 'captionsdisabled');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -957,7 +954,7 @@ class Plyr {
|
|||||||
// Trigger event on change
|
// Trigger event on change
|
||||||
if (hiding !== isHidden) {
|
if (hiding !== isHidden) {
|
||||||
const eventName = hiding ? 'controlshidden' : 'controlsshown';
|
const eventName = hiding ? 'controlshidden' : 'controlsshown';
|
||||||
trigger.call(this, this.media, eventName);
|
triggerEvent.call(this, this.media, eventName);
|
||||||
}
|
}
|
||||||
return !hiding;
|
return !hiding;
|
||||||
}
|
}
|
||||||
@ -970,9 +967,16 @@ class Plyr {
|
|||||||
* @param {function} callback - Callback for when event occurs
|
* @param {function} callback - Callback for when event occurs
|
||||||
*/
|
*/
|
||||||
on(event, callback) {
|
on(event, callback) {
|
||||||
on(this.elements.container, event, callback);
|
on.call(this, this.elements.container, event, callback);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Add event listeners once
|
||||||
|
* @param {string} event - Event type
|
||||||
|
* @param {function} callback - Callback for when event occurs
|
||||||
|
*/
|
||||||
|
once(event, callback) {
|
||||||
|
once(this.elements.container, event, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove event listeners
|
* Remove event listeners
|
||||||
* @param {string} event - Event type
|
* @param {string} event - Event type
|
||||||
@ -1023,13 +1027,13 @@ class Plyr {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Unbind listeners
|
// Unbind listeners
|
||||||
this.listeners.clear();
|
unbindListeners.call(this);
|
||||||
|
|
||||||
// Replace the container with the original element provided
|
// Replace the container with the original element provided
|
||||||
replaceElement(this.elements.original, this.elements.container);
|
replaceElement(this.elements.original, this.elements.container);
|
||||||
|
|
||||||
// Event
|
// Event
|
||||||
trigger.call(this, this.elements.original, 'destroyed', true);
|
triggerEvent.call(this, this.elements.original, 'destroyed', true);
|
||||||
|
|
||||||
// Callback
|
// Callback
|
||||||
if (is.function(callback)) {
|
if (is.function(callback)) {
|
||||||
|
@ -8,7 +8,7 @@ import i18n from './i18n';
|
|||||||
import support from './support';
|
import support from './support';
|
||||||
import browser from './utils/browser';
|
import browser from './utils/browser';
|
||||||
import { getElement, toggleClass, toggleState } from './utils/elements';
|
import { getElement, toggleClass, toggleState } from './utils/elements';
|
||||||
import { trigger } from './utils/events';
|
import { triggerEvent } from './utils/events';
|
||||||
import is from './utils/is';
|
import is from './utils/is';
|
||||||
import loadImage from './utils/loadImage';
|
import loadImage from './utils/loadImage';
|
||||||
|
|
||||||
@ -102,7 +102,7 @@ const ui = {
|
|||||||
|
|
||||||
// Ready event at end of execution stack
|
// Ready event at end of execution stack
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
trigger.call(this, this.media, 'ready');
|
triggerEvent.call(this, this.media, 'ready');
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
// Set the title
|
// Set the title
|
||||||
|
@ -27,7 +27,7 @@ const supportsPassiveListeners = (() => {
|
|||||||
})();
|
})();
|
||||||
|
|
||||||
// Toggle event listener
|
// Toggle event listener
|
||||||
export function toggleListener(elements, event, callback, toggle = false, passive = true, capture = false) {
|
export function toggleListener(elements, event, callback, toggle = false, passive = true, capture = false, once = false) {
|
||||||
// Bail if no elemetns, event, or callback
|
// Bail if no elemetns, event, or callback
|
||||||
if (is.empty(elements) || is.empty(event) || !is.function(callback)) {
|
if (is.empty(elements) || is.empty(event) || !is.function(callback)) {
|
||||||
return;
|
return;
|
||||||
@ -64,22 +64,37 @@ export function toggleListener(elements, event, callback, toggle = false, passiv
|
|||||||
|
|
||||||
// If a single node is passed, bind the event listener
|
// If a single node is passed, bind the event listener
|
||||||
events.forEach(type => {
|
events.forEach(type => {
|
||||||
|
if (this && this.eventListeners && toggle && !once) {
|
||||||
|
// Cache event listener
|
||||||
|
this.eventListeners.push({ elements, type, callback, options });
|
||||||
|
}
|
||||||
|
|
||||||
elements[toggle ? 'addEventListener' : 'removeEventListener'](type, callback, options);
|
elements[toggle ? 'addEventListener' : 'removeEventListener'](type, callback, options);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bind event handler
|
// Bind event handler
|
||||||
export function on(element, events = '', callback, passive = true, capture = false) {
|
export function on(element, events = '', callback, passive = true, capture = false) {
|
||||||
toggleListener(element, events, callback, true, passive, capture);
|
toggleListener.call(this, element, events, callback, true, passive, capture);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unbind event handler
|
// Unbind event handler
|
||||||
export function off(element, events = '', callback, passive = true, capture = false) {
|
export function off(element, events = '', callback, passive = true, capture = false) {
|
||||||
toggleListener(element, events, callback, false, passive, capture);
|
toggleListener.call(this, element, events, callback, false, passive, capture);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind once-only event handler
|
||||||
|
export function once(element, events = '', callback, passive = true, capture = false) {
|
||||||
|
function onceCallback(...args) {
|
||||||
|
off(element, events, onceCallback, passive, capture);
|
||||||
|
callback.apply(this, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleListener(element, events, onceCallback, true, passive, capture, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trigger event
|
// Trigger event
|
||||||
export function trigger(element, type = '', bubbles = false, detail = {}) {
|
export function triggerEvent(element, type = '', bubbles = false, detail = {}) {
|
||||||
// Bail if no element
|
// Bail if no element
|
||||||
if (!is.element(element) || is.empty(type)) {
|
if (!is.element(element) || is.empty(type)) {
|
||||||
return;
|
return;
|
||||||
@ -96,3 +111,15 @@ export function trigger(element, type = '', bubbles = false, detail = {}) {
|
|||||||
// Dispatch the event
|
// Dispatch the event
|
||||||
element.dispatchEvent(event);
|
element.dispatchEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unbind all cached event listeners
|
||||||
|
export function unbindListeners() {
|
||||||
|
if (this && this.eventListeners) {
|
||||||
|
this.eventListeners.forEach(item => {
|
||||||
|
const { elements, type, callback, options } = item;
|
||||||
|
elements.removeEventListener(type, callback, options);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.eventListeners = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user