Linting changes
This commit is contained in:
parent
02321c35bc
commit
9a69ae2599
@ -56,7 +56,7 @@ const captions = {
|
|||||||
if (browser.isIE && window.URL) {
|
if (browser.isIE && window.URL) {
|
||||||
const elements = this.media.querySelectorAll('track');
|
const elements = this.media.querySelectorAll('track');
|
||||||
|
|
||||||
Array.from(elements).forEach(track => {
|
Array.from(elements).forEach((track) => {
|
||||||
const src = track.getAttribute('src');
|
const src = track.getAttribute('src');
|
||||||
const url = parseUrl(src);
|
const url = parseUrl(src);
|
||||||
|
|
||||||
@ -66,7 +66,7 @@ const captions = {
|
|||||||
['http:', 'https:'].includes(url.protocol)
|
['http:', 'https:'].includes(url.protocol)
|
||||||
) {
|
) {
|
||||||
fetch(src, 'blob')
|
fetch(src, 'blob')
|
||||||
.then(blob => {
|
.then((blob) => {
|
||||||
track.setAttribute('src', window.URL.createObjectURL(blob));
|
track.setAttribute('src', window.URL.createObjectURL(blob));
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
@ -84,7 +84,7 @@ const captions = {
|
|||||||
// * toggled: The real captions state
|
// * toggled: The real captions state
|
||||||
|
|
||||||
const browserLanguages = navigator.languages || [navigator.language || navigator.userLanguage || 'en'];
|
const browserLanguages = navigator.languages || [navigator.language || navigator.userLanguage || 'en'];
|
||||||
const languages = dedupe(browserLanguages.map(language => language.split('-')[0]));
|
const languages = dedupe(browserLanguages.map((language) => language.split('-')[0]));
|
||||||
let language = (this.storage.get('language') || this.config.captions.language || 'auto').toLowerCase();
|
let language = (this.storage.get('language') || this.config.captions.language || 'auto').toLowerCase();
|
||||||
|
|
||||||
// Use first browser language when language is 'auto'
|
// Use first browser language when language is 'auto'
|
||||||
@ -119,13 +119,13 @@ const captions = {
|
|||||||
const tracks = captions.getTracks.call(this, true);
|
const tracks = captions.getTracks.call(this, true);
|
||||||
// Get the wanted language
|
// Get the wanted language
|
||||||
const { active, language, meta, currentTrackNode } = this.captions;
|
const { active, language, meta, currentTrackNode } = this.captions;
|
||||||
const languageExists = Boolean(tracks.find(track => track.language === language));
|
const languageExists = Boolean(tracks.find((track) => track.language === language));
|
||||||
|
|
||||||
// Handle tracks (add event listener and "pseudo"-default)
|
// Handle tracks (add event listener and "pseudo"-default)
|
||||||
if (this.isHTML5 && this.isVideo) {
|
if (this.isHTML5 && this.isVideo) {
|
||||||
tracks
|
tracks
|
||||||
.filter(track => !meta.get(track))
|
.filter((track) => !meta.get(track))
|
||||||
.forEach(track => {
|
.forEach((track) => {
|
||||||
this.debug.log('Track added', track);
|
this.debug.log('Track added', track);
|
||||||
|
|
||||||
// Attempt to store if the original dom element was "default"
|
// Attempt to store if the original dom element was "default"
|
||||||
@ -309,19 +309,19 @@ const captions = {
|
|||||||
// For HTML5, use cache instead of current tracks when it exists (if captions.update is false)
|
// For HTML5, use cache instead of current tracks when it exists (if captions.update is false)
|
||||||
// Filter out removed tracks and tracks that aren't captions/subtitles (for example metadata)
|
// Filter out removed tracks and tracks that aren't captions/subtitles (for example metadata)
|
||||||
return tracks
|
return tracks
|
||||||
.filter(track => !this.isHTML5 || update || this.captions.meta.has(track))
|
.filter((track) => !this.isHTML5 || update || this.captions.meta.has(track))
|
||||||
.filter(track => ['captions', 'subtitles'].includes(track.kind));
|
.filter((track) => ['captions', 'subtitles'].includes(track.kind));
|
||||||
},
|
},
|
||||||
|
|
||||||
// Match tracks based on languages and get the first
|
// Match tracks based on languages and get the first
|
||||||
findTrack(languages, force = false) {
|
findTrack(languages, force = false) {
|
||||||
const tracks = captions.getTracks.call(this);
|
const tracks = captions.getTracks.call(this);
|
||||||
const sortIsDefault = track => Number((this.captions.meta.get(track) || {}).default);
|
const sortIsDefault = (track) => Number((this.captions.meta.get(track) || {}).default);
|
||||||
const sorted = Array.from(tracks).sort((a, b) => sortIsDefault(b) - sortIsDefault(a));
|
const sorted = Array.from(tracks).sort((a, b) => sortIsDefault(b) - sortIsDefault(a));
|
||||||
let track;
|
let track;
|
||||||
|
|
||||||
languages.every(language => {
|
languages.every((language) => {
|
||||||
track = sorted.find(t => t.language === language);
|
track = sorted.find((t) => t.language === language);
|
||||||
return !track; // Break iteration if there is a match
|
return !track; // Break iteration if there is a match
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -383,12 +383,12 @@ const captions = {
|
|||||||
const track = captions.getCurrentTrack.call(this);
|
const track = captions.getCurrentTrack.call(this);
|
||||||
|
|
||||||
cues = Array.from((track || {}).activeCues || [])
|
cues = Array.from((track || {}).activeCues || [])
|
||||||
.map(cue => cue.getCueAsHTML())
|
.map((cue) => cue.getCueAsHTML())
|
||||||
.map(getHTML);
|
.map(getHTML);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set new caption text
|
// Set new caption text
|
||||||
const content = cues.map(cueText => cueText.trim()).join('\n');
|
const content = cues.map((cueText) => cueText.trim()).join('\n');
|
||||||
const changed = content !== this.elements.captions.innerHTML;
|
const changed = content !== this.elements.captions.innerHTML;
|
||||||
|
|
||||||
if (changed) {
|
if (changed) {
|
||||||
|
52
src/js/controls.js
vendored
52
src/js/controls.js
vendored
@ -179,7 +179,7 @@ const controls = {
|
|||||||
iconPressed: null,
|
iconPressed: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
['element', 'icon', 'label'].forEach(key => {
|
['element', 'icon', 'label'].forEach((key) => {
|
||||||
if (Object.keys(attributes).includes(key)) {
|
if (Object.keys(attributes).includes(key)) {
|
||||||
props[key] = attributes[key];
|
props[key] = attributes[key];
|
||||||
delete attributes[key];
|
delete attributes[key];
|
||||||
@ -193,7 +193,7 @@ const controls = {
|
|||||||
|
|
||||||
// Set class name
|
// Set class name
|
||||||
if (Object.keys(attributes).includes('class')) {
|
if (Object.keys(attributes).includes('class')) {
|
||||||
if (!attributes.class.split(' ').some(c => c === this.config.classNames.control)) {
|
if (!attributes.class.split(' ').some((c) => c === this.config.classNames.control)) {
|
||||||
extend(attributes, {
|
extend(attributes, {
|
||||||
class: `${attributes.class} ${this.config.classNames.control}`,
|
class: `${attributes.class} ${this.config.classNames.control}`,
|
||||||
});
|
});
|
||||||
@ -401,7 +401,7 @@ const controls = {
|
|||||||
this,
|
this,
|
||||||
menuItem,
|
menuItem,
|
||||||
'keydown keyup',
|
'keydown keyup',
|
||||||
event => {
|
(event) => {
|
||||||
// We only care about space and ⬆️ ⬇️️ ➡️
|
// We only care about space and ⬆️ ⬇️️ ➡️
|
||||||
if (![32, 38, 39, 40].includes(event.which)) {
|
if (![32, 38, 39, 40].includes(event.which)) {
|
||||||
return;
|
return;
|
||||||
@ -448,7 +448,7 @@ const controls = {
|
|||||||
|
|
||||||
// Enter will fire a `click` event but we still need to manage focus
|
// Enter will fire a `click` event but we still need to manage focus
|
||||||
// So we bind to keyup which fires after and set focus here
|
// So we bind to keyup which fires after and set focus here
|
||||||
on.call(this, menuItem, 'keyup', event => {
|
on.call(this, menuItem, 'keyup', (event) => {
|
||||||
if (event.which !== 13) {
|
if (event.which !== 13) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -493,8 +493,8 @@ const controls = {
|
|||||||
// Ensure exclusivity
|
// Ensure exclusivity
|
||||||
if (check) {
|
if (check) {
|
||||||
Array.from(menuItem.parentNode.children)
|
Array.from(menuItem.parentNode.children)
|
||||||
.filter(node => matches(node, '[role="menuitemradio"]'))
|
.filter((node) => matches(node, '[role="menuitemradio"]'))
|
||||||
.forEach(node => node.setAttribute('aria-checked', 'false'));
|
.forEach((node) => node.setAttribute('aria-checked', 'false'));
|
||||||
}
|
}
|
||||||
|
|
||||||
menuItem.setAttribute('aria-checked', check ? 'true' : 'false');
|
menuItem.setAttribute('aria-checked', check ? 'true' : 'false');
|
||||||
@ -504,7 +504,7 @@ const controls = {
|
|||||||
this.listeners.bind(
|
this.listeners.bind(
|
||||||
menuItem,
|
menuItem,
|
||||||
'click keyup',
|
'click keyup',
|
||||||
event => {
|
(event) => {
|
||||||
if (is.keyboardEvent(event) && event.which !== 32) {
|
if (is.keyboardEvent(event) && event.which !== 32) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -698,7 +698,7 @@ const controls = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const visible = `${this.config.classNames.tooltip}--visible`;
|
const visible = `${this.config.classNames.tooltip}--visible`;
|
||||||
const toggle = show => toggleClass(this.elements.display.seekTooltip, visible, show);
|
const toggle = (show) => toggleClass(this.elements.display.seekTooltip, visible, show);
|
||||||
|
|
||||||
// Hide on touch
|
// Hide on touch
|
||||||
if (this.touch) {
|
if (this.touch) {
|
||||||
@ -894,7 +894,7 @@ const controls = {
|
|||||||
|
|
||||||
// Set options if passed and filter based on uniqueness and config
|
// Set options if passed and filter based on uniqueness and config
|
||||||
if (is.array(options)) {
|
if (is.array(options)) {
|
||||||
this.options.quality = dedupe(options).filter(quality => this.config.quality.options.includes(quality));
|
this.options.quality = dedupe(options).filter((quality) => this.config.quality.options.includes(quality));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Toggle the pane and tab
|
// Toggle the pane and tab
|
||||||
@ -913,7 +913,7 @@ const controls = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the badge HTML for HD, 4K etc
|
// Get the badge HTML for HD, 4K etc
|
||||||
const getBadge = quality => {
|
const getBadge = (quality) => {
|
||||||
const label = i18n.get(`qualityBadge.${quality}`, this.config);
|
const label = i18n.get(`qualityBadge.${quality}`, this.config);
|
||||||
|
|
||||||
if (!label.length) {
|
if (!label.length) {
|
||||||
@ -929,7 +929,7 @@ const controls = {
|
|||||||
const sorting = this.config.quality.options;
|
const sorting = this.config.quality.options;
|
||||||
return sorting.indexOf(a) > sorting.indexOf(b) ? 1 : -1;
|
return sorting.indexOf(a) > sorting.indexOf(b) ? 1 : -1;
|
||||||
})
|
})
|
||||||
.forEach(quality => {
|
.forEach((quality) => {
|
||||||
controls.createMenuItem.call(this, {
|
controls.createMenuItem.call(this, {
|
||||||
value: quality,
|
value: quality,
|
||||||
list,
|
list,
|
||||||
@ -1052,7 +1052,7 @@ const controls = {
|
|||||||
const list = this.elements.settings.panels.speed.querySelector('[role="menu"]');
|
const list = this.elements.settings.panels.speed.querySelector('[role="menu"]');
|
||||||
|
|
||||||
// Filter out invalid speeds
|
// Filter out invalid speeds
|
||||||
this.options.speed = this.options.speed.filter(o => o >= this.minimumSpeed && o <= this.maximumSpeed);
|
this.options.speed = this.options.speed.filter((o) => o >= this.minimumSpeed && o <= this.maximumSpeed);
|
||||||
|
|
||||||
// Toggle the pane and tab
|
// Toggle the pane and tab
|
||||||
const toggle = !is.empty(this.options.speed) && this.options.speed.length > 1;
|
const toggle = !is.empty(this.options.speed) && this.options.speed.length > 1;
|
||||||
@ -1070,7 +1070,7 @@ const controls = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create items
|
// Create items
|
||||||
this.options.speed.forEach(speed => {
|
this.options.speed.forEach((speed) => {
|
||||||
controls.createMenuItem.call(this, {
|
controls.createMenuItem.call(this, {
|
||||||
value: speed,
|
value: speed,
|
||||||
list,
|
list,
|
||||||
@ -1085,7 +1085,7 @@ const controls = {
|
|||||||
// Check if we need to hide/show the settings menu
|
// Check if we need to hide/show the settings menu
|
||||||
checkMenu() {
|
checkMenu() {
|
||||||
const { buttons } = this.elements.settings;
|
const { buttons } = this.elements.settings;
|
||||||
const visible = !is.empty(buttons) && Object.values(buttons).some(button => !button.hidden);
|
const visible = !is.empty(buttons) && Object.values(buttons).some((button) => !button.hidden);
|
||||||
|
|
||||||
toggleHidden(this.elements.settings.menu, !visible);
|
toggleHidden(this.elements.settings.menu, !visible);
|
||||||
},
|
},
|
||||||
@ -1099,7 +1099,7 @@ const controls = {
|
|||||||
let target = pane;
|
let target = pane;
|
||||||
|
|
||||||
if (!is.element(target)) {
|
if (!is.element(target)) {
|
||||||
target = Object.values(this.elements.settings.panels).find(p => !p.hidden);
|
target = Object.values(this.elements.settings.panels).find((p) => !p.hidden);
|
||||||
}
|
}
|
||||||
|
|
||||||
const firstItem = target.querySelector('[role^="menuitem"]');
|
const firstItem = target.querySelector('[role^="menuitem"]');
|
||||||
@ -1191,7 +1191,7 @@ const controls = {
|
|||||||
|
|
||||||
// Hide all other panels
|
// Hide all other panels
|
||||||
const container = target.parentNode;
|
const container = target.parentNode;
|
||||||
const current = Array.from(container.children).find(node => !node.hidden);
|
const current = Array.from(container.children).find((node) => !node.hidden);
|
||||||
|
|
||||||
// If we can do fancy animations, we'll animate the height/width
|
// If we can do fancy animations, we'll animate the height/width
|
||||||
if (support.transitions && !support.reducedMotion) {
|
if (support.transitions && !support.reducedMotion) {
|
||||||
@ -1203,7 +1203,7 @@ const controls = {
|
|||||||
const size = controls.getMenuSize.call(this, target);
|
const size = controls.getMenuSize.call(this, target);
|
||||||
|
|
||||||
// Restore auto height/width
|
// Restore auto height/width
|
||||||
const restore = event => {
|
const restore = (event) => {
|
||||||
// We're only bothered about height and width on the container
|
// We're only bothered about height and width on the container
|
||||||
if (event.target !== container || !['width', 'height'].includes(event.propertyName)) {
|
if (event.target !== container || !['width', 'height'].includes(event.propertyName)) {
|
||||||
return;
|
return;
|
||||||
@ -1275,7 +1275,7 @@ const controls = {
|
|||||||
const defaultAttributes = { class: 'plyr__controls__item' };
|
const defaultAttributes = { class: 'plyr__controls__item' };
|
||||||
|
|
||||||
// Loop through controls in order
|
// Loop through controls in order
|
||||||
dedupe(is.array(this.config.controls) ? this.config.controls: []).forEach(control => {
|
dedupe(is.array(this.config.controls) ? this.config.controls : []).forEach((control) => {
|
||||||
// Restart button
|
// Restart button
|
||||||
if (control === 'restart') {
|
if (control === 'restart') {
|
||||||
container.appendChild(createButton.call(this, 'restart', defaultAttributes));
|
container.appendChild(createButton.call(this, 'restart', defaultAttributes));
|
||||||
@ -1437,7 +1437,7 @@ const controls = {
|
|||||||
this.elements.settings.panels.home = home;
|
this.elements.settings.panels.home = home;
|
||||||
|
|
||||||
// Build the menu items
|
// Build the menu items
|
||||||
this.config.settings.forEach(type => {
|
this.config.settings.forEach((type) => {
|
||||||
// TODO: bundle this with the createMenuItem helper and bindings
|
// TODO: bundle this with the createMenuItem helper and bindings
|
||||||
const menuItem = createElement(
|
const menuItem = createElement(
|
||||||
'button',
|
'button',
|
||||||
@ -1510,7 +1510,7 @@ const controls = {
|
|||||||
this,
|
this,
|
||||||
pane,
|
pane,
|
||||||
'keydown',
|
'keydown',
|
||||||
event => {
|
(event) => {
|
||||||
// We only care about <-
|
// We only care about <-
|
||||||
if (event.which !== 37) {
|
if (event.which !== 37) {
|
||||||
return;
|
return;
|
||||||
@ -1661,7 +1661,7 @@ const controls = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Replace props with their value
|
// Replace props with their value
|
||||||
const replace = input => {
|
const replace = (input) => {
|
||||||
let result = input;
|
let result = input;
|
||||||
|
|
||||||
Object.entries(props).forEach(([key, value]) => {
|
Object.entries(props).forEach(([key, value]) => {
|
||||||
@ -1702,7 +1702,7 @@ const controls = {
|
|||||||
|
|
||||||
// Add pressed property to buttons
|
// Add pressed property to buttons
|
||||||
if (!is.empty(this.elements.buttons)) {
|
if (!is.empty(this.elements.buttons)) {
|
||||||
const addProperty = button => {
|
const addProperty = (button) => {
|
||||||
const className = this.config.classNames.controlPressed;
|
const className = this.config.classNames.controlPressed;
|
||||||
Object.defineProperty(button, 'pressed', {
|
Object.defineProperty(button, 'pressed', {
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
@ -1718,11 +1718,9 @@ const controls = {
|
|||||||
// Toggle classname when pressed property is set
|
// Toggle classname when pressed property is set
|
||||||
Object.values(this.elements.buttons)
|
Object.values(this.elements.buttons)
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.forEach(button => {
|
.forEach((button) => {
|
||||||
if (is.array(button) || is.nodeList(button)) {
|
if (is.array(button) || is.nodeList(button)) {
|
||||||
Array.from(button)
|
Array.from(button).filter(Boolean).forEach(addProperty);
|
||||||
.filter(Boolean)
|
|
||||||
.forEach(addProperty);
|
|
||||||
} else {
|
} else {
|
||||||
addProperty(button);
|
addProperty(button);
|
||||||
}
|
}
|
||||||
@ -1740,7 +1738,7 @@ const controls = {
|
|||||||
const selector = `${selectors.controls.wrapper} ${selectors.labels} .${classNames.hidden}`;
|
const selector = `${selectors.controls.wrapper} ${selectors.labels} .${classNames.hidden}`;
|
||||||
const labels = getElements.call(this, selector);
|
const labels = getElements.call(this, selector);
|
||||||
|
|
||||||
Array.from(labels).forEach(label => {
|
Array.from(labels).forEach((label) => {
|
||||||
toggleClass(label, this.config.classNames.hidden, false);
|
toggleClass(label, this.config.classNames.hidden, false);
|
||||||
toggleClass(label, this.config.classNames.tooltip, true);
|
toggleClass(label, this.config.classNames.tooltip, true);
|
||||||
});
|
});
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
import browser from './utils/browser';
|
import browser from './utils/browser';
|
||||||
import { closest,getElements, hasClass, toggleClass } from './utils/elements';
|
import { closest, getElements, hasClass, toggleClass } from './utils/elements';
|
||||||
import { on, triggerEvent } from './utils/events';
|
import { on, triggerEvent } from './utils/events';
|
||||||
import is from './utils/is';
|
import is from './utils/is';
|
||||||
import { silencePromise } from './utils/promise';
|
import { silencePromise } from './utils/promise';
|
||||||
@ -43,7 +43,7 @@ class Fullscreen {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Fullscreen toggle on double click
|
// Fullscreen toggle on double click
|
||||||
on.call(this.player, this.player.elements.container, 'dblclick', event => {
|
on.call(this.player, this.player.elements.container, 'dblclick', (event) => {
|
||||||
// Ignore double click in controls
|
// 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;
|
||||||
@ -53,7 +53,7 @@ class Fullscreen {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Tap focus when in fullscreen
|
// Tap focus when in fullscreen
|
||||||
on.call(this, this.player.elements.container, 'keydown', event => this.trapFocus(event));
|
on.call(this, this.player.elements.container, 'keydown', (event) => this.trapFocus(event));
|
||||||
|
|
||||||
// Update the UI
|
// Update the UI
|
||||||
this.update();
|
this.update();
|
||||||
@ -85,7 +85,7 @@ class Fullscreen {
|
|||||||
let value = '';
|
let value = '';
|
||||||
const prefixes = ['webkit', 'moz', 'ms'];
|
const prefixes = ['webkit', 'moz', 'ms'];
|
||||||
|
|
||||||
prefixes.some(pre => {
|
prefixes.some((pre) => {
|
||||||
if (is.function(document[`${pre}ExitFullscreen`]) || is.function(document[`${pre}CancelFullScreen`])) {
|
if (is.function(document[`${pre}ExitFullscreen`]) || is.function(document[`${pre}CancelFullScreen`])) {
|
||||||
value = pre;
|
value = pre;
|
||||||
return true;
|
return true;
|
||||||
@ -189,7 +189,7 @@ class Fullscreen {
|
|||||||
} else if (this.cleanupViewport) {
|
} else if (this.cleanupViewport) {
|
||||||
viewport.content = viewport.content
|
viewport.content = viewport.content
|
||||||
.split(',')
|
.split(',')
|
||||||
.filter(part => part.trim() !== property)
|
.filter((part) => part.trim() !== property)
|
||||||
.join(',');
|
.join(',');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ const html5 = {
|
|||||||
const sources = Array.from(this.media.querySelectorAll('source'));
|
const sources = Array.from(this.media.querySelectorAll('source'));
|
||||||
|
|
||||||
// Filter out unsupported sources (if type is specified)
|
// Filter out unsupported sources (if type is specified)
|
||||||
return sources.filter(source => {
|
return sources.filter((source) => {
|
||||||
const type = source.getAttribute('type');
|
const type = source.getAttribute('type');
|
||||||
|
|
||||||
if (is.empty(type)) {
|
if (is.empty(type)) {
|
||||||
@ -39,7 +39,7 @@ const html5 = {
|
|||||||
// Get sizes from <source> elements
|
// Get sizes from <source> elements
|
||||||
return html5.getSources
|
return html5.getSources
|
||||||
.call(this)
|
.call(this)
|
||||||
.map(source => Number(source.getAttribute('size')))
|
.map((source) => Number(source.getAttribute('size')))
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ const html5 = {
|
|||||||
get() {
|
get() {
|
||||||
// Get sources
|
// Get sources
|
||||||
const sources = html5.getSources.call(player);
|
const sources = html5.getSources.call(player);
|
||||||
const source = sources.find(s => s.getAttribute('src') === player.source);
|
const source = sources.find((s) => s.getAttribute('src') === player.source);
|
||||||
|
|
||||||
// Return size, if match is found
|
// Return size, if match is found
|
||||||
return source && Number(source.getAttribute('size'));
|
return source && Number(source.getAttribute('size'));
|
||||||
@ -80,7 +80,7 @@ const html5 = {
|
|||||||
// Get sources
|
// Get sources
|
||||||
const sources = html5.getSources.call(player);
|
const sources = html5.getSources.call(player);
|
||||||
// Get first match for requested size
|
// Get first match for requested size
|
||||||
const source = sources.find(s => Number(s.getAttribute('size')) === input);
|
const source = sources.find((s) => Number(s.getAttribute('size')) === input);
|
||||||
|
|
||||||
// No matching source found
|
// No matching source found
|
||||||
if (!source) {
|
if (!source) {
|
||||||
|
@ -277,7 +277,7 @@ class Listeners {
|
|||||||
player,
|
player,
|
||||||
elements.container,
|
elements.container,
|
||||||
'mousemove mouseleave touchstart touchmove enterfullscreen exitfullscreen',
|
'mousemove mouseleave touchstart touchmove enterfullscreen exitfullscreen',
|
||||||
event => {
|
(event) => {
|
||||||
const { controls: controlsElement } = elements;
|
const { controls: controlsElement } = elements;
|
||||||
|
|
||||||
// Remove button states for fullscreen
|
// Remove button states for fullscreen
|
||||||
@ -319,7 +319,7 @@ class Listeners {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Resize on fullscreen change
|
// Resize on fullscreen change
|
||||||
const setPlayerSize = measure => {
|
const setPlayerSize = (measure) => {
|
||||||
// If we don't need to measure the viewport
|
// If we don't need to measure the viewport
|
||||||
if (!measure) {
|
if (!measure) {
|
||||||
return setAspectRatio.call(player);
|
return setAspectRatio.call(player);
|
||||||
@ -336,7 +336,7 @@ class Listeners {
|
|||||||
timers.resized = setTimeout(setPlayerSize, 50);
|
timers.resized = setTimeout(setPlayerSize, 50);
|
||||||
};
|
};
|
||||||
|
|
||||||
on.call(player, elements.container, 'enterfullscreen exitfullscreen', event => {
|
on.call(player, elements.container, 'enterfullscreen exitfullscreen', (event) => {
|
||||||
const { target, usingNative } = player.fullscreen;
|
const { target, usingNative } = player.fullscreen;
|
||||||
|
|
||||||
// Ignore events not from target
|
// Ignore events not from target
|
||||||
@ -373,10 +373,10 @@ class Listeners {
|
|||||||
const { elements } = player;
|
const { elements } = player;
|
||||||
|
|
||||||
// Time change on media
|
// Time change on media
|
||||||
on.call(player, player.media, 'timeupdate seeking seeked', event => controls.timeUpdate.call(player, event));
|
on.call(player, player.media, 'timeupdate seeking seeked', (event) => controls.timeUpdate.call(player, event));
|
||||||
|
|
||||||
// Display duration
|
// Display duration
|
||||||
on.call(player, player.media, 'durationchange loadeddata loadedmetadata', event =>
|
on.call(player, player.media, 'durationchange loadeddata loadedmetadata', (event) =>
|
||||||
controls.durationUpdate.call(player, event),
|
controls.durationUpdate.call(player, event),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -393,20 +393,20 @@ class Listeners {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Check for buffer progress
|
// Check for buffer progress
|
||||||
on.call(player, player.media, 'progress playing seeking seeked', event =>
|
on.call(player, player.media, 'progress playing seeking seeked', (event) =>
|
||||||
controls.updateProgress.call(player, event),
|
controls.updateProgress.call(player, event),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Handle volume changes
|
// Handle volume changes
|
||||||
on.call(player, player.media, 'volumechange', event => controls.updateVolume.call(player, event));
|
on.call(player, player.media, 'volumechange', (event) => controls.updateVolume.call(player, event));
|
||||||
|
|
||||||
// Handle play/pause
|
// Handle play/pause
|
||||||
on.call(player, player.media, 'playing play pause ended emptied timeupdate', event =>
|
on.call(player, player.media, 'playing play pause ended emptied timeupdate', (event) =>
|
||||||
ui.checkPlaying.call(player, event),
|
ui.checkPlaying.call(player, event),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Loading state
|
// Loading state
|
||||||
on.call(player, player.media, 'waiting canplay seeked playing', event => ui.checkLoading.call(player, event));
|
on.call(player, player.media, 'waiting canplay seeked playing', (event) => ui.checkLoading.call(player, event));
|
||||||
|
|
||||||
// Click video
|
// Click video
|
||||||
if (player.supported.ui && player.config.clickToPlay && !player.isAudio) {
|
if (player.supported.ui && player.config.clickToPlay && !player.isAudio) {
|
||||||
@ -419,7 +419,7 @@ class Listeners {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// On click play, pause or restart
|
// On click play, pause or restart
|
||||||
on.call(player, elements.container, 'click', event => {
|
on.call(player, elements.container, 'click', (event) => {
|
||||||
const targets = [elements.container, wrapper];
|
const targets = [elements.container, wrapper];
|
||||||
|
|
||||||
// Ignore if click if not container or in video wrapper
|
// Ignore if click if not container or in video wrapper
|
||||||
@ -459,7 +459,7 @@ class Listeners {
|
|||||||
player,
|
player,
|
||||||
elements.wrapper,
|
elements.wrapper,
|
||||||
'contextmenu',
|
'contextmenu',
|
||||||
event => {
|
(event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
@ -485,7 +485,7 @@ class Listeners {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Quality change
|
// Quality change
|
||||||
on.call(player, player.media, 'qualitychange', event => {
|
on.call(player, player.media, 'qualitychange', (event) => {
|
||||||
// Update UI
|
// Update UI
|
||||||
controls.updateSetting.call(player, 'quality', null, event.detail.quality);
|
controls.updateSetting.call(player, 'quality', null, event.detail.quality);
|
||||||
});
|
});
|
||||||
@ -499,7 +499,7 @@ class Listeners {
|
|||||||
// Bubble up key events for Edge
|
// Bubble up key events for Edge
|
||||||
const proxyEvents = player.config.events.concat(['keyup', 'keydown']).join(' ');
|
const proxyEvents = player.config.events.concat(['keyup', 'keydown']).join(' ');
|
||||||
|
|
||||||
on.call(player, player.media, proxyEvents, event => {
|
on.call(player, player.media, proxyEvents, (event) => {
|
||||||
let { detail = {} } = event;
|
let { detail = {} } = event;
|
||||||
|
|
||||||
// Get error details from media
|
// Get error details from media
|
||||||
@ -539,7 +539,7 @@ class Listeners {
|
|||||||
player,
|
player,
|
||||||
element,
|
element,
|
||||||
type,
|
type,
|
||||||
event => this.proxy(event, defaultHandler, customHandlerKey),
|
(event) => this.proxy(event, defaultHandler, customHandlerKey),
|
||||||
passive && !hasCustomHandler,
|
passive && !hasCustomHandler,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -553,7 +553,7 @@ class Listeners {
|
|||||||
|
|
||||||
// Play/pause toggle
|
// Play/pause toggle
|
||||||
if (elements.buttons.play) {
|
if (elements.buttons.play) {
|
||||||
Array.from(elements.buttons.play).forEach(button => {
|
Array.from(elements.buttons.play).forEach((button) => {
|
||||||
this.bind(
|
this.bind(
|
||||||
button,
|
button,
|
||||||
'click',
|
'click',
|
||||||
@ -624,7 +624,7 @@ class Listeners {
|
|||||||
this.bind(
|
this.bind(
|
||||||
elements.buttons.settings,
|
elements.buttons.settings,
|
||||||
'click',
|
'click',
|
||||||
event => {
|
(event) => {
|
||||||
// Prevent the document click listener closing the menu
|
// Prevent the document click listener closing the menu
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@ -641,7 +641,7 @@ class Listeners {
|
|||||||
this.bind(
|
this.bind(
|
||||||
elements.buttons.settings,
|
elements.buttons.settings,
|
||||||
'keyup',
|
'keyup',
|
||||||
event => {
|
(event) => {
|
||||||
const code = event.which;
|
const code = event.which;
|
||||||
|
|
||||||
// We only care about space and return
|
// We only care about space and return
|
||||||
@ -669,21 +669,21 @@ class Listeners {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Escape closes menu
|
// Escape closes menu
|
||||||
this.bind(elements.settings.menu, 'keydown', event => {
|
this.bind(elements.settings.menu, 'keydown', (event) => {
|
||||||
if (event.which === 27) {
|
if (event.which === 27) {
|
||||||
controls.toggleMenu.call(player, event);
|
controls.toggleMenu.call(player, event);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Set range input alternative "value", which matches the tooltip time (#954)
|
// Set range input alternative "value", which matches the tooltip time (#954)
|
||||||
this.bind(elements.inputs.seek, 'mousedown mousemove', event => {
|
this.bind(elements.inputs.seek, 'mousedown mousemove', (event) => {
|
||||||
const rect = elements.progress.getBoundingClientRect();
|
const rect = elements.progress.getBoundingClientRect();
|
||||||
const percent = (100 / rect.width) * (event.pageX - rect.left);
|
const percent = (100 / rect.width) * (event.pageX - rect.left);
|
||||||
event.currentTarget.setAttribute('seek-value', percent);
|
event.currentTarget.setAttribute('seek-value', percent);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Pause while seeking
|
// Pause while seeking
|
||||||
this.bind(elements.inputs.seek, 'mousedown mouseup keydown keyup touchstart touchend', event => {
|
this.bind(elements.inputs.seek, 'mousedown mouseup keydown keyup touchstart touchend', (event) => {
|
||||||
const seek = event.currentTarget;
|
const seek = event.currentTarget;
|
||||||
const code = event.keyCode ? event.keyCode : event.which;
|
const code = event.keyCode ? event.keyCode : event.which;
|
||||||
const attribute = 'play-on-seeked';
|
const attribute = 'play-on-seeked';
|
||||||
@ -715,14 +715,14 @@ class Listeners {
|
|||||||
// it takes over further interactions on the page. This is a hack
|
// it takes over further interactions on the page. This is a hack
|
||||||
if (browser.isIos) {
|
if (browser.isIos) {
|
||||||
const inputs = getElements.call(player, 'input[type="range"]');
|
const inputs = getElements.call(player, 'input[type="range"]');
|
||||||
Array.from(inputs).forEach(input => this.bind(input, inputEvent, event => repaint(event.target)));
|
Array.from(inputs).forEach((input) => this.bind(input, inputEvent, (event) => repaint(event.target)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Seek
|
// Seek
|
||||||
this.bind(
|
this.bind(
|
||||||
elements.inputs.seek,
|
elements.inputs.seek,
|
||||||
inputEvent,
|
inputEvent,
|
||||||
event => {
|
(event) => {
|
||||||
const seek = event.currentTarget;
|
const seek = event.currentTarget;
|
||||||
// If it exists, use seek-value instead of "value" for consistency with tooltip time (#954)
|
// If it exists, use seek-value instead of "value" for consistency with tooltip time (#954)
|
||||||
let seekTo = seek.getAttribute('seek-value');
|
let seekTo = seek.getAttribute('seek-value');
|
||||||
@ -739,13 +739,13 @@ class Listeners {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Seek tooltip
|
// Seek tooltip
|
||||||
this.bind(elements.progress, 'mouseenter mouseleave mousemove', event =>
|
this.bind(elements.progress, 'mouseenter mouseleave mousemove', (event) =>
|
||||||
controls.updateSeekTooltip.call(player, event),
|
controls.updateSeekTooltip.call(player, event),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Preview thumbnails plugin
|
// Preview thumbnails plugin
|
||||||
// TODO: Really need to work on some sort of plug-in wide event bus or pub-sub for this
|
// TODO: Really need to work on some sort of plug-in wide event bus or pub-sub for this
|
||||||
this.bind(elements.progress, 'mousemove touchmove', event => {
|
this.bind(elements.progress, 'mousemove touchmove', (event) => {
|
||||||
const { previewThumbnails } = player;
|
const { previewThumbnails } = player;
|
||||||
|
|
||||||
if (previewThumbnails && previewThumbnails.loaded) {
|
if (previewThumbnails && previewThumbnails.loaded) {
|
||||||
@ -763,7 +763,7 @@ class Listeners {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Show scrubbing preview
|
// Show scrubbing preview
|
||||||
this.bind(elements.progress, 'mousedown touchstart', event => {
|
this.bind(elements.progress, 'mousedown touchstart', (event) => {
|
||||||
const { previewThumbnails } = player;
|
const { previewThumbnails } = player;
|
||||||
|
|
||||||
if (previewThumbnails && previewThumbnails.loaded) {
|
if (previewThumbnails && previewThumbnails.loaded) {
|
||||||
@ -771,7 +771,7 @@ class Listeners {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.bind(elements.progress, 'mouseup touchend', event => {
|
this.bind(elements.progress, 'mouseup touchend', (event) => {
|
||||||
const { previewThumbnails } = player;
|
const { previewThumbnails } = player;
|
||||||
|
|
||||||
if (previewThumbnails && previewThumbnails.loaded) {
|
if (previewThumbnails && previewThumbnails.loaded) {
|
||||||
@ -781,8 +781,8 @@ class Listeners {
|
|||||||
|
|
||||||
// Polyfill for lower fill in <input type="range"> for webkit
|
// Polyfill for lower fill in <input type="range"> for webkit
|
||||||
if (browser.isWebkit) {
|
if (browser.isWebkit) {
|
||||||
Array.from(getElements.call(player, 'input[type="range"]')).forEach(element => {
|
Array.from(getElements.call(player, 'input[type="range"]')).forEach((element) => {
|
||||||
this.bind(element, 'input', event => controls.updateRangeFill.call(player, event.target));
|
this.bind(element, 'input', (event) => controls.updateRangeFill.call(player, event.target));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -805,30 +805,30 @@ class Listeners {
|
|||||||
this.bind(
|
this.bind(
|
||||||
elements.inputs.volume,
|
elements.inputs.volume,
|
||||||
inputEvent,
|
inputEvent,
|
||||||
event => {
|
(event) => {
|
||||||
player.volume = event.target.value;
|
player.volume = event.target.value;
|
||||||
},
|
},
|
||||||
'volume',
|
'volume',
|
||||||
);
|
);
|
||||||
|
|
||||||
// Update controls.hover state (used for ui.toggleControls to avoid hiding when interacting)
|
// Update controls.hover state (used for ui.toggleControls to avoid hiding when interacting)
|
||||||
this.bind(elements.controls, 'mouseenter mouseleave', event => {
|
this.bind(elements.controls, 'mouseenter mouseleave', (event) => {
|
||||||
elements.controls.hover = !player.touch && event.type === 'mouseenter';
|
elements.controls.hover = !player.touch && event.type === 'mouseenter';
|
||||||
});
|
});
|
||||||
|
|
||||||
// Also update controls.hover state for any non-player children of fullscreen element (as above)
|
// Also update controls.hover state for any non-player children of fullscreen element (as above)
|
||||||
if (elements.fullscreen) {
|
if (elements.fullscreen) {
|
||||||
Array.from(elements.fullscreen.children)
|
Array.from(elements.fullscreen.children)
|
||||||
.filter(c => !c.contains(elements.container))
|
.filter((c) => !c.contains(elements.container))
|
||||||
.forEach(child => {
|
.forEach((child) => {
|
||||||
this.bind(child, 'mouseenter mouseleave', event => {
|
this.bind(child, 'mouseenter mouseleave', (event) => {
|
||||||
elements.controls.hover = !player.touch && event.type === 'mouseenter';
|
elements.controls.hover = !player.touch && event.type === 'mouseenter';
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update controls.pressed state (used for ui.toggleControls to avoid hiding when interacting)
|
// Update controls.pressed state (used for ui.toggleControls to avoid hiding when interacting)
|
||||||
this.bind(elements.controls, 'mousedown mouseup touchstart touchend touchcancel', event => {
|
this.bind(elements.controls, 'mousedown mouseup touchstart touchend touchcancel', (event) => {
|
||||||
elements.controls.pressed = ['mousedown', 'touchstart'].includes(event.type);
|
elements.controls.pressed = ['mousedown', 'touchstart'].includes(event.type);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -861,12 +861,12 @@ class Listeners {
|
|||||||
this.bind(
|
this.bind(
|
||||||
elements.inputs.volume,
|
elements.inputs.volume,
|
||||||
'wheel',
|
'wheel',
|
||||||
event => {
|
(event) => {
|
||||||
// Detect "natural" scroll - suppored on OS X Safari only
|
// Detect "natural" scroll - suppored on OS X Safari only
|
||||||
// Other browsers on OS X will be inverted until support improves
|
// Other browsers on OS X will be inverted until support improves
|
||||||
const inverted = event.webkitDirectionInvertedFromDevice;
|
const inverted = event.webkitDirectionInvertedFromDevice;
|
||||||
// Get delta from event. Invert if `inverted` is true
|
// Get delta from event. Invert if `inverted` is true
|
||||||
const [x, y] = [event.deltaX, -event.deltaY].map(value => (inverted ? -value : value));
|
const [x, y] = [event.deltaX, -event.deltaY].map((value) => (inverted ? -value : value));
|
||||||
// Using the biggest delta, normalize to 1 or -1 (or 0 if no delta)
|
// Using the biggest delta, normalize to 1 or -1 (or 0 if no delta)
|
||||||
const direction = Math.sign(Math.abs(x) > Math.abs(y) ? x : y);
|
const direction = Math.sign(Math.abs(x) > Math.abs(y) ? x : y);
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ import { silencePromise } from '../utils/promise';
|
|||||||
import { formatTime } from '../utils/time';
|
import { formatTime } from '../utils/time';
|
||||||
import { buildUrlParams } from '../utils/urls';
|
import { buildUrlParams } from '../utils/urls';
|
||||||
|
|
||||||
const destroy = instance => {
|
const destroy = (instance) => {
|
||||||
// Destroy our adsManager
|
// Destroy our adsManager
|
||||||
if (instance.manager) {
|
if (instance.manager) {
|
||||||
instance.manager.destroy();
|
instance.manager.destroy();
|
||||||
@ -179,10 +179,10 @@ class Ads {
|
|||||||
// Listen and respond to ads loaded and error events
|
// Listen and respond to ads loaded and error events
|
||||||
this.loader.addEventListener(
|
this.loader.addEventListener(
|
||||||
google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED,
|
google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED,
|
||||||
event => this.onAdsManagerLoaded(event),
|
(event) => this.onAdsManagerLoaded(event),
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
this.loader.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, error => this.onAdError(error), false);
|
this.loader.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, (error) => this.onAdError(error), false);
|
||||||
|
|
||||||
// Request video ads to be pre-loaded
|
// Request video ads to be pre-loaded
|
||||||
this.requestAds();
|
this.requestAds();
|
||||||
@ -264,11 +264,11 @@ class Ads {
|
|||||||
|
|
||||||
// Add listeners to the required events
|
// Add listeners to the required events
|
||||||
// Advertisement error events
|
// Advertisement error events
|
||||||
this.manager.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, error => this.onAdError(error));
|
this.manager.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, (error) => this.onAdError(error));
|
||||||
|
|
||||||
// Advertisement regular events
|
// Advertisement regular events
|
||||||
Object.keys(google.ima.AdEvent.Type).forEach(type => {
|
Object.keys(google.ima.AdEvent.Type).forEach((type) => {
|
||||||
this.manager.addEventListener(google.ima.AdEvent.Type[type], e => this.onAdEvent(e));
|
this.manager.addEventListener(google.ima.AdEvent.Type[type], (e) => this.onAdEvent(e));
|
||||||
});
|
});
|
||||||
|
|
||||||
// Resolve our adsManager
|
// Resolve our adsManager
|
||||||
@ -278,7 +278,7 @@ class Ads {
|
|||||||
addCuePoints() {
|
addCuePoints() {
|
||||||
// Add advertisement cue's within the time line if available
|
// Add advertisement cue's within the time line if available
|
||||||
if (!is.empty(this.cuePoints)) {
|
if (!is.empty(this.cuePoints)) {
|
||||||
this.cuePoints.forEach(cuePoint => {
|
this.cuePoints.forEach((cuePoint) => {
|
||||||
if (cuePoint !== 0 && cuePoint !== -1 && cuePoint < this.player.duration) {
|
if (cuePoint !== 0 && cuePoint !== -1 && cuePoint < this.player.duration) {
|
||||||
const seekElement = this.player.elements.progress;
|
const seekElement = this.player.elements.progress;
|
||||||
|
|
||||||
@ -310,7 +310,7 @@ class Ads {
|
|||||||
const adData = event.getAdData();
|
const adData = event.getAdData();
|
||||||
|
|
||||||
// Proxy event
|
// Proxy event
|
||||||
const dispatchEvent = type => {
|
const dispatchEvent = (type) => {
|
||||||
triggerEvent.call(this.player, this.player.media, `ads${type.replace(/_/g, '').toLowerCase()}`);
|
triggerEvent.call(this.player, this.player.media, `ads${type.replace(/_/g, '').toLowerCase()}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -565,7 +565,7 @@ class Ads {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Re-set our adsManager promises
|
// Re-set our adsManager promises
|
||||||
this.managerPromise = new Promise(resolve => {
|
this.managerPromise = new Promise((resolve) => {
|
||||||
this.on('loaded', resolve);
|
this.on('loaded', resolve);
|
||||||
this.player.debug.log(this.manager);
|
this.player.debug.log(this.manager);
|
||||||
});
|
});
|
||||||
@ -586,7 +586,7 @@ class Ads {
|
|||||||
const handlers = this.events[event];
|
const handlers = this.events[event];
|
||||||
|
|
||||||
if (is.array(handlers)) {
|
if (is.array(handlers)) {
|
||||||
handlers.forEach(handler => {
|
handlers.forEach((handler) => {
|
||||||
if (is.function(handler)) {
|
if (is.function(handler)) {
|
||||||
handler.apply(this, args);
|
handler.apply(this, args);
|
||||||
}
|
}
|
||||||
|
@ -5,15 +5,15 @@ import is from '../utils/is';
|
|||||||
import { formatTime } from '../utils/time';
|
import { formatTime } from '../utils/time';
|
||||||
|
|
||||||
// Arg: vttDataString example: "WEBVTT\n\n1\n00:00:05.000 --> 00:00:10.000\n1080p-00001.jpg"
|
// Arg: vttDataString example: "WEBVTT\n\n1\n00:00:05.000 --> 00:00:10.000\n1080p-00001.jpg"
|
||||||
const parseVtt = vttDataString => {
|
const parseVtt = (vttDataString) => {
|
||||||
const processedList = [];
|
const processedList = [];
|
||||||
const frames = vttDataString.split(/\r\n\r\n|\n\n|\r\r/);
|
const frames = vttDataString.split(/\r\n\r\n|\n\n|\r\r/);
|
||||||
|
|
||||||
frames.forEach(frame => {
|
frames.forEach((frame) => {
|
||||||
const result = {};
|
const result = {};
|
||||||
const lines = frame.split(/\r\n|\n|\r/);
|
const lines = frame.split(/\r\n|\n|\r/);
|
||||||
|
|
||||||
lines.forEach(line => {
|
lines.forEach((line) => {
|
||||||
if (!is.number(result.startTime)) {
|
if (!is.number(result.startTime)) {
|
||||||
// The line with start and end times on it is the first line of interest
|
// The line with start and end times on it is the first line of interest
|
||||||
const matchTimes = line.match(
|
const matchTimes = line.match(
|
||||||
@ -130,7 +130,7 @@ class PreviewThumbnails {
|
|||||||
|
|
||||||
// Download VTT files and parse them
|
// Download VTT files and parse them
|
||||||
getThumbnails() {
|
getThumbnails() {
|
||||||
return new Promise(resolve => {
|
return new Promise((resolve) => {
|
||||||
const { src } = this.player.config.previewThumbnails;
|
const { src } = this.player.config.previewThumbnails;
|
||||||
|
|
||||||
if (is.empty(src)) {
|
if (is.empty(src)) {
|
||||||
@ -149,7 +149,7 @@ class PreviewThumbnails {
|
|||||||
|
|
||||||
// Via callback()
|
// Via callback()
|
||||||
if (is.function(src)) {
|
if (is.function(src)) {
|
||||||
src(thumbnails => {
|
src((thumbnails) => {
|
||||||
this.thumbnails = thumbnails;
|
this.thumbnails = thumbnails;
|
||||||
sortAndResolve();
|
sortAndResolve();
|
||||||
});
|
});
|
||||||
@ -159,7 +159,7 @@ class PreviewThumbnails {
|
|||||||
// If string, convert into single-element list
|
// If string, convert into single-element list
|
||||||
const urls = is.string(src) ? [src] : src;
|
const urls = is.string(src) ? [src] : src;
|
||||||
// Loop through each src URL. Download and process the VTT file, storing the resulting data in this.thumbnails
|
// Loop through each src URL. Download and process the VTT file, storing the resulting data in this.thumbnails
|
||||||
const promises = urls.map(u => this.getThumbnail(u));
|
const promises = urls.map((u) => this.getThumbnail(u));
|
||||||
// Resolve
|
// Resolve
|
||||||
Promise.all(promises).then(sortAndResolve);
|
Promise.all(promises).then(sortAndResolve);
|
||||||
}
|
}
|
||||||
@ -168,8 +168,8 @@ class PreviewThumbnails {
|
|||||||
|
|
||||||
// Process individual VTT file
|
// Process individual VTT file
|
||||||
getThumbnail(url) {
|
getThumbnail(url) {
|
||||||
return new Promise(resolve => {
|
return new Promise((resolve) => {
|
||||||
fetch(url).then(response => {
|
fetch(url).then((response) => {
|
||||||
const thumbnail = {
|
const thumbnail = {
|
||||||
frames: parseVtt(response),
|
frames: parseVtt(response),
|
||||||
height: null,
|
height: null,
|
||||||
@ -360,7 +360,7 @@ class PreviewThumbnails {
|
|||||||
// Find the desired thumbnail index
|
// Find the desired thumbnail index
|
||||||
// TODO: Handle a video longer than the thumbs where thumbNum is null
|
// TODO: Handle a video longer than the thumbs where thumbNum is null
|
||||||
const thumbNum = this.thumbnails[0].frames.findIndex(
|
const thumbNum = this.thumbnails[0].frames.findIndex(
|
||||||
frame => this.seekTime >= frame.startTime && this.seekTime <= frame.endTime,
|
(frame) => this.seekTime >= frame.startTime && this.seekTime <= frame.endTime,
|
||||||
);
|
);
|
||||||
const hasThumb = thumbNum >= 0;
|
const hasThumb = thumbNum >= 0;
|
||||||
let qualityIndex = 0;
|
let qualityIndex = 0;
|
||||||
@ -454,7 +454,7 @@ class PreviewThumbnails {
|
|||||||
// Remove all preview images that aren't the designated current image
|
// Remove all preview images that aren't the designated current image
|
||||||
removeOldImages(currentImage) {
|
removeOldImages(currentImage) {
|
||||||
// Get a list of all images, convert it from a DOM list to an array
|
// Get a list of all images, convert it from a DOM list to an array
|
||||||
Array.from(this.currentImageContainer.children).forEach(image => {
|
Array.from(this.currentImageContainer.children).forEach((image) => {
|
||||||
if (image.tagName.toLowerCase() !== 'img') {
|
if (image.tagName.toLowerCase() !== 'img') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -481,7 +481,7 @@ class PreviewThumbnails {
|
|||||||
// Preload images before and after the current one. Only if the user is still hovering/seeking the same frame
|
// Preload images before and after the current one. Only if the user is still hovering/seeking the same frame
|
||||||
// This will only preload the lowest quality
|
// This will only preload the lowest quality
|
||||||
preloadNearby(thumbNum, forward = true) {
|
preloadNearby(thumbNum, forward = true) {
|
||||||
return new Promise(resolve => {
|
return new Promise((resolve) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const oldThumbFilename = this.thumbnails[0].frames[thumbNum].text;
|
const oldThumbFilename = this.thumbnails[0].frames[thumbNum].text;
|
||||||
|
|
||||||
@ -496,7 +496,7 @@ class PreviewThumbnails {
|
|||||||
|
|
||||||
let foundOne = false;
|
let foundOne = false;
|
||||||
|
|
||||||
thumbnailsClone.forEach(frame => {
|
thumbnailsClone.forEach((frame) => {
|
||||||
const newThumbFilename = frame.text;
|
const newThumbFilename = frame.text;
|
||||||
|
|
||||||
if (newThumbFilename !== oldThumbFilename) {
|
if (newThumbFilename !== oldThumbFilename) {
|
||||||
|
@ -58,7 +58,7 @@ const vimeo = {
|
|||||||
.then(() => {
|
.then(() => {
|
||||||
vimeo.ready.call(player);
|
vimeo.ready.call(player);
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch((error) => {
|
||||||
player.debug.warn('Vimeo SDK (player.js) failed to load', error);
|
player.debug.warn('Vimeo SDK (player.js) failed to load', error);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -123,7 +123,7 @@ const vimeo = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get poster image
|
// Get poster image
|
||||||
fetch(format(player.config.urls.vimeo.api, id), 'json').then(response => {
|
fetch(format(player.config.urls.vimeo.api, id), 'json').then((response) => {
|
||||||
if (is.empty(response)) {
|
if (is.empty(response)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -269,11 +269,11 @@ const vimeo = {
|
|||||||
let currentSrc;
|
let currentSrc;
|
||||||
player.embed
|
player.embed
|
||||||
.getVideoUrl()
|
.getVideoUrl()
|
||||||
.then(value => {
|
.then((value) => {
|
||||||
currentSrc = value;
|
currentSrc = value;
|
||||||
controls.setDownloadUrl.call(player);
|
controls.setDownloadUrl.call(player);
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch((error) => {
|
||||||
this.debug.warn(error);
|
this.debug.warn(error);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -291,49 +291,49 @@ const vimeo = {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Set aspect ratio based on video size
|
// Set aspect ratio based on video size
|
||||||
Promise.all([player.embed.getVideoWidth(), player.embed.getVideoHeight()]).then(dimensions => {
|
Promise.all([player.embed.getVideoWidth(), player.embed.getVideoHeight()]).then((dimensions) => {
|
||||||
const [width, height] = dimensions;
|
const [width, height] = dimensions;
|
||||||
player.embed.ratio = [width, height];
|
player.embed.ratio = [width, height];
|
||||||
setAspectRatio.call(this);
|
setAspectRatio.call(this);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Set autopause
|
// Set autopause
|
||||||
player.embed.setAutopause(player.config.autopause).then(state => {
|
player.embed.setAutopause(player.config.autopause).then((state) => {
|
||||||
player.config.autopause = state;
|
player.config.autopause = state;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Get title
|
// Get title
|
||||||
player.embed.getVideoTitle().then(title => {
|
player.embed.getVideoTitle().then((title) => {
|
||||||
player.config.title = title;
|
player.config.title = title;
|
||||||
ui.setTitle.call(this);
|
ui.setTitle.call(this);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Get current time
|
// Get current time
|
||||||
player.embed.getCurrentTime().then(value => {
|
player.embed.getCurrentTime().then((value) => {
|
||||||
currentTime = value;
|
currentTime = value;
|
||||||
triggerEvent.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;
|
||||||
triggerEvent.call(player, player.media, 'durationchange');
|
triggerEvent.call(player, player.media, 'durationchange');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Get captions
|
// Get captions
|
||||||
player.embed.getTextTracks().then(tracks => {
|
player.embed.getTextTracks().then((tracks) => {
|
||||||
player.media.textTracks = tracks;
|
player.media.textTracks = tracks;
|
||||||
captions.setup.call(player);
|
captions.setup.call(player);
|
||||||
});
|
});
|
||||||
|
|
||||||
player.embed.on('cuechange', ({ cues = [] }) => {
|
player.embed.on('cuechange', ({ cues = [] }) => {
|
||||||
const strippedCues = cues.map(cue => stripHTML(cue.text));
|
const strippedCues = cues.map((cue) => stripHTML(cue.text));
|
||||||
captions.updateCues.call(player, strippedCues);
|
captions.updateCues.call(player, strippedCues);
|
||||||
});
|
});
|
||||||
|
|
||||||
player.embed.on('loaded', () => {
|
player.embed.on('loaded', () => {
|
||||||
// Assure state and events are updated on autoplay
|
// Assure state and events are updated on autoplay
|
||||||
player.embed.getPaused().then(paused => {
|
player.embed.getPaused().then((paused) => {
|
||||||
assurePlaybackState.call(player, !paused);
|
assurePlaybackState.call(player, !paused);
|
||||||
if (!paused) {
|
if (!paused) {
|
||||||
triggerEvent.call(player, player.media, 'playing');
|
triggerEvent.call(player, player.media, 'playing');
|
||||||
@ -366,13 +366,13 @@ const vimeo = {
|
|||||||
assurePlaybackState.call(player, false);
|
assurePlaybackState.call(player, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
player.embed.on('timeupdate', data => {
|
player.embed.on('timeupdate', (data) => {
|
||||||
player.media.seeking = false;
|
player.media.seeking = false;
|
||||||
currentTime = data.seconds;
|
currentTime = data.seconds;
|
||||||
triggerEvent.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;
|
||||||
triggerEvent.call(player, player.media, 'progress');
|
triggerEvent.call(player, player.media, 'progress');
|
||||||
|
|
||||||
@ -383,7 +383,7 @@ const vimeo = {
|
|||||||
|
|
||||||
// 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
|
||||||
// https://github.com/sampotts/plyr/issues/891
|
// https://github.com/sampotts/plyr/issues/891
|
||||||
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;
|
||||||
triggerEvent.call(player, player.media, 'durationchange');
|
triggerEvent.call(player, player.media, 'durationchange');
|
||||||
@ -401,7 +401,7 @@ const vimeo = {
|
|||||||
triggerEvent.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;
|
||||||
triggerEvent.call(player, player.media, 'error');
|
triggerEvent.call(player, player.media, 'error');
|
||||||
});
|
});
|
||||||
|
@ -70,7 +70,7 @@ const youtube = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Load the SDK
|
// Load the SDK
|
||||||
loadScript(this.config.urls.youtube.sdk).catch(error => {
|
loadScript(this.config.urls.youtube.sdk).catch((error) => {
|
||||||
this.debug.warn('YouTube API failed to load', error);
|
this.debug.warn('YouTube API failed to load', error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -81,7 +81,7 @@ const youtube = {
|
|||||||
const url = format(this.config.urls.youtube.api, videoId);
|
const url = format(this.config.urls.youtube.api, videoId);
|
||||||
|
|
||||||
fetch(url)
|
fetch(url)
|
||||||
.then(data => {
|
.then((data) => {
|
||||||
if (is.object(data)) {
|
if (is.object(data)) {
|
||||||
const { title, height, width } = data;
|
const { title, height, width } = data;
|
||||||
|
|
||||||
@ -128,14 +128,14 @@ const youtube = {
|
|||||||
player.media = replaceElement(container, player.media);
|
player.media = replaceElement(container, player.media);
|
||||||
|
|
||||||
// Id to poster wrapper
|
// Id to poster wrapper
|
||||||
const posterSrc = s => `https://i.ytimg.com/vi/${videoId}/${s}default.jpg`;
|
const posterSrc = (s) => `https://i.ytimg.com/vi/${videoId}/${s}default.jpg`;
|
||||||
|
|
||||||
// Check thumbnail images in order of quality, but reject fallback thumbnails (120px wide)
|
// Check thumbnail images in order of quality, but reject fallback thumbnails (120px wide)
|
||||||
loadImage(posterSrc('maxres'), 121) // Higest quality and unpadded
|
loadImage(posterSrc('maxres'), 121) // Higest quality and unpadded
|
||||||
.catch(() => loadImage(posterSrc('sd'), 121)) // 480p padded 4:3
|
.catch(() => loadImage(posterSrc('sd'), 121)) // 480p padded 4:3
|
||||||
.catch(() => loadImage(posterSrc('hq'))) // 360p padded 4:3. Always exists
|
.catch(() => loadImage(posterSrc('hq'))) // 360p padded 4:3. Always exists
|
||||||
.then(image => ui.setPoster.call(player, image.src))
|
.then((image) => ui.setPoster.call(player, image.src))
|
||||||
.then(src => {
|
.then((src) => {
|
||||||
// If the image is padded, use background-size "cover" instead (like youtube does too with their posters)
|
// If the image is padded, use background-size "cover" instead (like youtube does too with their posters)
|
||||||
if (!src.includes('maxres')) {
|
if (!src.includes('maxres')) {
|
||||||
player.elements.poster.style.backgroundSize = 'cover';
|
player.elements.poster.style.backgroundSize = 'cover';
|
||||||
@ -299,7 +299,7 @@ const youtube = {
|
|||||||
// Get available speeds
|
// Get available speeds
|
||||||
const speeds = instance.getAvailablePlaybackRates();
|
const speeds = instance.getAvailablePlaybackRates();
|
||||||
// Filter based on config
|
// Filter based on config
|
||||||
player.options.speed = speeds.filter(s => player.config.speed.options.includes(s));
|
player.options.speed = speeds.filter((s) => player.config.speed.options.includes(s));
|
||||||
|
|
||||||
// Set the tabindex to avoid focus entering iframe
|
// Set the tabindex to avoid focus entering iframe
|
||||||
if (player.supported.ui) {
|
if (player.supported.ui) {
|
||||||
|
@ -281,7 +281,7 @@ class Plyr {
|
|||||||
|
|
||||||
// Listen for events if debugging
|
// Listen for events if debugging
|
||||||
if (this.config.debug) {
|
if (this.config.debug) {
|
||||||
on.call(this, this.elements.container, this.config.events.join(' '), event => {
|
on.call(this, this.elements.container, this.config.events.join(' '), (event) => {
|
||||||
this.debug.log(`event: ${event.type}`);
|
this.debug.log(`event: ${event.type}`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1054,7 +1054,12 @@ class Plyr {
|
|||||||
const hiding = toggleClass(this.elements.container, this.config.classNames.hideControls, force);
|
const hiding = toggleClass(this.elements.container, this.config.classNames.hideControls, force);
|
||||||
|
|
||||||
// Close menu
|
// Close menu
|
||||||
if (hiding && is.array(this.config.controls) && this.config.controls.includes('settings') && !is.empty(this.config.settings)) {
|
if (
|
||||||
|
hiding &&
|
||||||
|
is.array(this.config.controls) &&
|
||||||
|
this.config.controls.includes('settings') &&
|
||||||
|
!is.empty(this.config.settings)
|
||||||
|
) {
|
||||||
controls.toggleMenu.call(this, false);
|
controls.toggleMenu.call(this, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1248,7 +1253,7 @@ class Plyr {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return targets.map(t => new Plyr(t, options));
|
return targets.map((t) => new Plyr(t, options));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ const source = {
|
|||||||
src: attributes,
|
src: attributes,
|
||||||
});
|
});
|
||||||
} else if (is.array(attributes)) {
|
} else if (is.array(attributes)) {
|
||||||
attributes.forEach(attribute => {
|
attributes.forEach((attribute) => {
|
||||||
insertElement(type, this.media, attribute);
|
insertElement(type, this.media, attribute);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
10
src/js/ui.js
10
src/js/ui.js
@ -135,7 +135,7 @@ const ui = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If there's a play button, set label
|
// If there's a play button, set label
|
||||||
Array.from(this.elements.buttons.play || []).forEach(button => {
|
Array.from(this.elements.buttons.play || []).forEach((button) => {
|
||||||
button.setAttribute('aria-label', label);
|
button.setAttribute('aria-label', label);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -178,7 +178,7 @@ const ui = {
|
|||||||
.call(this)
|
.call(this)
|
||||||
// Load image
|
// Load image
|
||||||
.then(() => loadImage(poster))
|
.then(() => loadImage(poster))
|
||||||
.catch(err => {
|
.catch((err) => {
|
||||||
// Hide poster on error unless it's been set by another call
|
// Hide poster on error unless it's been set by another call
|
||||||
if (poster === this.poster) {
|
if (poster === this.poster) {
|
||||||
ui.togglePoster.call(this, false);
|
ui.togglePoster.call(this, false);
|
||||||
@ -214,7 +214,7 @@ const ui = {
|
|||||||
toggleClass(this.elements.container, this.config.classNames.stopped, this.stopped);
|
toggleClass(this.elements.container, this.config.classNames.stopped, this.stopped);
|
||||||
|
|
||||||
// Set state
|
// Set state
|
||||||
Array.from(this.elements.buttons.play || []).forEach(target => {
|
Array.from(this.elements.buttons.play || []).forEach((target) => {
|
||||||
Object.assign(target, { pressed: this.playing });
|
Object.assign(target, { pressed: this.playing });
|
||||||
target.setAttribute('aria-label', i18n.get(this.playing ? 'pause' : 'play', this.config));
|
target.setAttribute('aria-label', i18n.get(this.playing ? 'pause' : 'play', this.config));
|
||||||
});
|
});
|
||||||
@ -270,8 +270,8 @@ const ui = {
|
|||||||
// Loop through values (as they are the keys when the object is spread 🤔)
|
// Loop through values (as they are the keys when the object is spread 🤔)
|
||||||
Object.values({ ...this.media.style })
|
Object.values({ ...this.media.style })
|
||||||
// We're only fussed about Plyr specific properties
|
// We're only fussed about Plyr specific properties
|
||||||
.filter(key => !is.empty(key) && key.startsWith('--plyr'))
|
.filter((key) => !is.empty(key) && key.startsWith('--plyr'))
|
||||||
.forEach(key => {
|
.forEach((key) => {
|
||||||
// Set on the container
|
// Set on the container
|
||||||
this.elements.container.style.setProperty(key, this.media.style.getPropertyValue(key));
|
this.elements.container.style.setProperty(key, this.media.style.getPropertyValue(key));
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ export const transitionEndEvent = (() => {
|
|||||||
transition: 'transitionend',
|
transition: 'transitionend',
|
||||||
};
|
};
|
||||||
|
|
||||||
const type = Object.keys(events).find(event => element.style[event] !== undefined);
|
const type = Object.keys(events).find((event) => element.style[event] !== undefined);
|
||||||
|
|
||||||
return is.string(type) ? events[type] : false;
|
return is.string(type) ? events[type] : false;
|
||||||
})();
|
})();
|
||||||
|
@ -138,7 +138,7 @@ export function getAttributesFromSelector(sel, existingAttributes) {
|
|||||||
const attributes = {};
|
const attributes = {};
|
||||||
const existing = extend({}, existingAttributes);
|
const existing = extend({}, existingAttributes);
|
||||||
|
|
||||||
sel.split(',').forEach(s => {
|
sel.split(',').forEach((s) => {
|
||||||
// Remove whitespace
|
// Remove whitespace
|
||||||
const selector = s.trim();
|
const selector = s.trim();
|
||||||
const className = selector.replace('.', '');
|
const className = selector.replace('.', '');
|
||||||
@ -198,7 +198,7 @@ export function toggleHidden(element, hidden) {
|
|||||||
// Mirror Element.classList.toggle, with IE compatibility for "force" argument
|
// Mirror Element.classList.toggle, with IE compatibility for "force" argument
|
||||||
export function toggleClass(element, className, force) {
|
export function toggleClass(element, className, force) {
|
||||||
if (is.nodeList(element)) {
|
if (is.nodeList(element)) {
|
||||||
return Array.from(element).map(e => toggleClass(e, className, force));
|
return Array.from(element).map((e) => toggleClass(e, className, force));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is.element(element)) {
|
if (is.element(element)) {
|
||||||
|
@ -50,7 +50,7 @@ export function toggleListener(element, event, callback, toggle = false, passive
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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) {
|
if (this && this.eventListeners && toggle) {
|
||||||
// Cache event listener
|
// Cache event listener
|
||||||
this.eventListeners.push({ element, type, callback, options });
|
this.eventListeners.push({ element, type, callback, options });
|
||||||
@ -100,7 +100,7 @@ export function triggerEvent(element, type = '', bubbles = false, detail = {}) {
|
|||||||
// Unbind all cached event listeners
|
// Unbind all cached event listeners
|
||||||
export function unbindListeners() {
|
export function unbindListeners() {
|
||||||
if (this && this.eventListeners) {
|
if (this && this.eventListeners) {
|
||||||
this.eventListeners.forEach(item => {
|
this.eventListeners.forEach((item) => {
|
||||||
const { element, type, callback, options } = item;
|
const { element, type, callback, options } = item;
|
||||||
element.removeEventListener(type, callback, options);
|
element.removeEventListener(type, callback, options);
|
||||||
});
|
});
|
||||||
@ -111,7 +111,7 @@ export function unbindListeners() {
|
|||||||
|
|
||||||
// Run method when / if player is ready
|
// Run method when / if player is ready
|
||||||
export function ready() {
|
export function ready() {
|
||||||
return new Promise(resolve =>
|
return new Promise((resolve) =>
|
||||||
this.ready ? setTimeout(resolve, 0) : on.call(this, this.elements.container, 'ready', resolve),
|
this.ready ? setTimeout(resolve, 0) : on.call(this, this.elements.container, 'ready', resolve),
|
||||||
).then(() => {});
|
).then(() => {});
|
||||||
}
|
}
|
||||||
|
@ -2,31 +2,31 @@
|
|||||||
// Type checking utils
|
// Type checking utils
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
const getConstructor = input => (input !== null && typeof input !== 'undefined' ? input.constructor : null);
|
const getConstructor = (input) => (input !== null && typeof input !== 'undefined' ? input.constructor : null);
|
||||||
const instanceOf = (input, constructor) => Boolean(input && constructor && input instanceof constructor);
|
const instanceOf = (input, constructor) => Boolean(input && constructor && input instanceof constructor);
|
||||||
const isNullOrUndefined = input => input === null || typeof input === 'undefined';
|
const isNullOrUndefined = (input) => input === null || typeof input === 'undefined';
|
||||||
const isObject = input => getConstructor(input) === Object;
|
const isObject = (input) => getConstructor(input) === Object;
|
||||||
const isNumber = input => getConstructor(input) === Number && !Number.isNaN(input);
|
const isNumber = (input) => getConstructor(input) === Number && !Number.isNaN(input);
|
||||||
const isString = input => getConstructor(input) === String;
|
const isString = (input) => getConstructor(input) === String;
|
||||||
const isBoolean = input => getConstructor(input) === Boolean;
|
const isBoolean = (input) => getConstructor(input) === Boolean;
|
||||||
const isFunction = input => getConstructor(input) === Function;
|
const isFunction = (input) => getConstructor(input) === Function;
|
||||||
const isArray = input => Array.isArray(input);
|
const isArray = (input) => Array.isArray(input);
|
||||||
const isWeakMap = input => instanceOf(input, WeakMap);
|
const isWeakMap = (input) => instanceOf(input, WeakMap);
|
||||||
const isNodeList = input => instanceOf(input, NodeList);
|
const isNodeList = (input) => instanceOf(input, NodeList);
|
||||||
const isElement = input => instanceOf(input, Element);
|
const isElement = (input) => instanceOf(input, Element);
|
||||||
const isTextNode = input => getConstructor(input) === Text;
|
const isTextNode = (input) => getConstructor(input) === Text;
|
||||||
const isEvent = input => instanceOf(input, Event);
|
const isEvent = (input) => instanceOf(input, Event);
|
||||||
const isKeyboardEvent = input => instanceOf(input, KeyboardEvent);
|
const isKeyboardEvent = (input) => instanceOf(input, KeyboardEvent);
|
||||||
const isCue = input => instanceOf(input, window.TextTrackCue) || instanceOf(input, window.VTTCue);
|
const isCue = (input) => instanceOf(input, window.TextTrackCue) || instanceOf(input, window.VTTCue);
|
||||||
const isTrack = input => instanceOf(input, TextTrack) || (!isNullOrUndefined(input) && isString(input.kind));
|
const isTrack = (input) => instanceOf(input, TextTrack) || (!isNullOrUndefined(input) && isString(input.kind));
|
||||||
const isPromise = input => instanceOf(input, Promise) && isFunction(input.then);
|
const isPromise = (input) => instanceOf(input, Promise) && isFunction(input.then);
|
||||||
|
|
||||||
const isEmpty = input =>
|
const isEmpty = (input) =>
|
||||||
isNullOrUndefined(input) ||
|
isNullOrUndefined(input) ||
|
||||||
((isString(input) || isArray(input) || isNodeList(input)) && !input.length) ||
|
((isString(input) || isArray(input) || isNodeList(input)) && !input.length) ||
|
||||||
(isObject(input) && !Object.keys(input).length);
|
(isObject(input) && !Object.keys(input).length);
|
||||||
|
|
||||||
const isUrl = input => {
|
const isUrl = (input) => {
|
||||||
// Accept a URL object
|
// Accept a URL object
|
||||||
if (instanceOf(input, window.URL)) {
|
if (instanceOf(input, window.URL)) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -54,7 +54,7 @@ export default function loadSprite(url, id) {
|
|||||||
|
|
||||||
// Get the sprite
|
// Get the sprite
|
||||||
fetch(url)
|
fetch(url)
|
||||||
.then(result => {
|
.then((result) => {
|
||||||
if (is.empty(result)) {
|
if (is.empty(result)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ export function extend(target = {}, ...sources) {
|
|||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.keys(source).forEach(key => {
|
Object.keys(source).forEach((key) => {
|
||||||
if (is.object(source[key])) {
|
if (is.object(source[key])) {
|
||||||
if (!Object.keys(target).includes(key)) {
|
if (!Object.keys(target).includes(key)) {
|
||||||
Object.assign(target, { [key]: {} });
|
Object.assign(target, { [key]: {} });
|
||||||
|
@ -33,7 +33,7 @@ export const replaceAll = (input = '', find = '', replace = '') =>
|
|||||||
|
|
||||||
// Convert to title case
|
// Convert to title case
|
||||||
export const toTitleCase = (input = '') =>
|
export const toTitleCase = (input = '') =>
|
||||||
input.toString().replace(/\w\S*/g, text => text.charAt(0).toUpperCase() + text.substr(1).toLowerCase());
|
input.toString().replace(/\w\S*/g, (text) => text.charAt(0).toUpperCase() + text.substr(1).toLowerCase());
|
||||||
|
|
||||||
// Convert string to pascalCase
|
// Convert string to pascalCase
|
||||||
export function toPascalCase(input = '') {
|
export function toPascalCase(input = '') {
|
||||||
|
@ -27,7 +27,7 @@ export function reduceAspectRatio(ratio) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getAspectRatio(input) {
|
export function getAspectRatio(input) {
|
||||||
const parse = ratio => (validateRatio(ratio) ? ratio.split(':').map(Number) : null);
|
const parse = (ratio) => (validateRatio(ratio) ? ratio.split(':').map(Number) : null);
|
||||||
// Try provided ratio
|
// Try provided ratio
|
||||||
let ratio = parse(input);
|
let ratio = parse(input);
|
||||||
|
|
||||||
|
@ -5,9 +5,9 @@
|
|||||||
import is from './is';
|
import is from './is';
|
||||||
|
|
||||||
// Time helpers
|
// Time helpers
|
||||||
export const getHours = value => Math.trunc((value / 60 / 60) % 60, 10);
|
export const getHours = (value) => Math.trunc((value / 60 / 60) % 60, 10);
|
||||||
export const getMinutes = value => Math.trunc((value / 60) % 60, 10);
|
export const getMinutes = (value) => Math.trunc((value / 60) % 60, 10);
|
||||||
export const getSeconds = value => Math.trunc(value % 60, 10);
|
export const getSeconds = (value) => Math.trunc(value % 60, 10);
|
||||||
|
|
||||||
// Format time to UI friendly string
|
// Format time to UI friendly string
|
||||||
export function formatTime(time = 0, displayHours = false, inverted = false) {
|
export function formatTime(time = 0, displayHours = false, inverted = false) {
|
||||||
@ -17,7 +17,7 @@ export function formatTime(time = 0, displayHours = false, inverted = false) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Format time component to add leading zero
|
// Format time component to add leading zero
|
||||||
const format = value => `0${value}`.slice(-2);
|
const format = (value) => `0${value}`.slice(-2);
|
||||||
// Breakdown to hours, mins, secs
|
// Breakdown to hours, mins, secs
|
||||||
let hours = getHours(time);
|
let hours = getHours(time);
|
||||||
const mins = getMinutes(time);
|
const mins = getMinutes(time);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user