Controls rewrite
This commit is contained in:
parent
684107da5c
commit
ef1d73df15
4
dist/plyr.js
vendored
4
dist/plyr.js
vendored
File diff suppressed because one or more lines are too long
644
src/js/plyr.js
644
src/js/plyr.js
@ -104,16 +104,14 @@
|
|||||||
volume: '[data-plyr="volume"]'
|
volume: '[data-plyr="volume"]'
|
||||||
},
|
},
|
||||||
display: {
|
display: {
|
||||||
volume: '.plyr__volume--display',
|
|
||||||
currentTime: '.plyr__time--current',
|
currentTime: '.plyr__time--current',
|
||||||
duration: '.plyr__time--duration'
|
duration: '.plyr__time--duration',
|
||||||
},
|
|
||||||
progress: {
|
|
||||||
container: '.plyr__progress',
|
|
||||||
buffer: '.plyr__progress--buffer',
|
buffer: '.plyr__progress--buffer',
|
||||||
played: '.plyr__progress--played',
|
played: '.plyr__progress--played',
|
||||||
loop: '.plyr__progress-loop'
|
loop: '.plyr__progress--loop',
|
||||||
|
volume: '.plyr__volume--display',
|
||||||
},
|
},
|
||||||
|
progress: '.plyr__progress',
|
||||||
captions: '.plyr__captions',
|
captions: '.plyr__captions',
|
||||||
menu: {
|
menu: {
|
||||||
quality: '.js-plyr__menu__list--quality'
|
quality: '.js-plyr__menu__list--quality'
|
||||||
@ -483,7 +481,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create a DocumentFragment
|
// Create a DocumentFragment
|
||||||
function createElement(type, attributes) {
|
function createElement(type, attributes, text) {
|
||||||
// Create a new <element>
|
// Create a new <element>
|
||||||
var element = document.createElement(type);
|
var element = document.createElement(type);
|
||||||
|
|
||||||
@ -492,14 +490,19 @@
|
|||||||
setAttributes(element, attributes);
|
setAttributes(element, attributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add text node
|
||||||
|
if (is.string(text)) {
|
||||||
|
element.appendChild(document.createTextNode(text));
|
||||||
|
}
|
||||||
|
|
||||||
// Return built element
|
// Return built element
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert a DocumentFragment
|
// Insert a DocumentFragment
|
||||||
function insertElement(type, parent, attributes) {
|
function insertElement(type, parent, attributes, text) {
|
||||||
// Create a new <element>
|
// Create a new <element>
|
||||||
var element = createElement(type, attributes);
|
var element = createElement(type, attributes, text);
|
||||||
|
|
||||||
// Inject the new element
|
// Inject the new element
|
||||||
prependChild(parent, element);
|
prependChild(parent, element);
|
||||||
@ -665,12 +668,20 @@
|
|||||||
|
|
||||||
// First object is the destination
|
// First object is the destination
|
||||||
var destination = Array.prototype.shift.call(objects);
|
var destination = Array.prototype.shift.call(objects);
|
||||||
|
if (!is.object(destination)) {
|
||||||
|
destination = {};
|
||||||
|
}
|
||||||
|
|
||||||
var length = objects.length;
|
var length = objects.length;
|
||||||
|
|
||||||
// Loop through all objects to merge
|
// Loop through all objects to merge
|
||||||
for (var i = 0; i < length; i++) {
|
for (var i = 0; i < length; i++) {
|
||||||
var source = objects[i];
|
var source = objects[i];
|
||||||
|
|
||||||
|
if (!is.object(source)) {
|
||||||
|
source = {};
|
||||||
|
}
|
||||||
|
|
||||||
for (var property in source) {
|
for (var property in source) {
|
||||||
if (source[property] && source[property].constructor && source[property].constructor === Object) {
|
if (source[property] && source[property].constructor && source[property].constructor === Object) {
|
||||||
destination[property] = destination[property] || {};
|
destination[property] = destination[property] || {};
|
||||||
@ -900,6 +911,63 @@
|
|||||||
log('Config', config);
|
log('Config', config);
|
||||||
log('Support', support);
|
log('Support', support);
|
||||||
|
|
||||||
|
// Find all elements
|
||||||
|
function getElements(selector) {
|
||||||
|
return plyr.container.querySelectorAll(selector);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find a single element
|
||||||
|
function getElement(selector) {
|
||||||
|
return getElements(selector)[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine if we're in an iframe
|
||||||
|
function inFrame() {
|
||||||
|
try {
|
||||||
|
return window.self !== window.top;
|
||||||
|
} catch (e) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trap focus inside container
|
||||||
|
function focusTrap() {
|
||||||
|
var tabbables = getElements('input:not([disabled]), button:not([disabled])'),
|
||||||
|
first = tabbables[0],
|
||||||
|
last = tabbables[tabbables.length - 1];
|
||||||
|
|
||||||
|
function checkFocus(event) {
|
||||||
|
// If it is TAB
|
||||||
|
if (event.which === 9 && plyr.isFullscreen) {
|
||||||
|
if (event.target === last && !event.shiftKey) {
|
||||||
|
// Move focus to first element that can be tabbed if Shift isn't used
|
||||||
|
event.preventDefault();
|
||||||
|
first.focus();
|
||||||
|
} else if (event.target === first && event.shiftKey) {
|
||||||
|
// Move focus to last element that can be tabbed if Shift is used
|
||||||
|
event.preventDefault();
|
||||||
|
last.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind the handler
|
||||||
|
on(plyr.container, 'keydown', checkFocus);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add elements to HTML5 media (source, tracks, etc)
|
||||||
|
function insertElements(type, attributes) {
|
||||||
|
if (is.string(attributes)) {
|
||||||
|
insertElement(type, plyr.media, {
|
||||||
|
src: attributes
|
||||||
|
});
|
||||||
|
} else if (attributes.constructor === Array) {
|
||||||
|
for (var i = attributes.length - 1; i >= 0; i--) {
|
||||||
|
insertElement(type, plyr.media, attributes[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Get icon URL
|
// Get icon URL
|
||||||
function getIconUrl() {
|
function getIconUrl() {
|
||||||
return {
|
return {
|
||||||
@ -925,16 +993,16 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create <svg> icon
|
// Create <svg> icon
|
||||||
function createIcon(type) {
|
function createIcon(type, attributes) {
|
||||||
var namespace = 'http://www.w3.org/2000/svg';
|
var namespace = 'http://www.w3.org/2000/svg';
|
||||||
var iconUrl = getIconUrl();
|
var iconUrl = getIconUrl();
|
||||||
var iconPath = (!iconUrl.absolute ? iconUrl.url : '') + '#' + config.iconPrefix;
|
var iconPath = (!iconUrl.absolute ? iconUrl.url : '') + '#' + config.iconPrefix;
|
||||||
|
|
||||||
// Create <svg>
|
// Create <svg>
|
||||||
var icon = document.createElementNS(namespace, 'svg');
|
var icon = document.createElementNS(namespace, 'svg');
|
||||||
setAttributes(icon, {
|
setAttributes(icon, extend(attributes, {
|
||||||
role: 'presentation'
|
role: 'presentation'
|
||||||
});
|
}));
|
||||||
|
|
||||||
// Create the <use> to reference sprite
|
// Create the <use> to reference sprite
|
||||||
var use = document.createElementNS(namespace, 'use');
|
var use = document.createElementNS(namespace, 'use');
|
||||||
@ -948,15 +1016,21 @@
|
|||||||
|
|
||||||
// Create hidden text label
|
// Create hidden text label
|
||||||
function createLabel(type) {
|
function createLabel(type) {
|
||||||
var label = createElement('span', {
|
var text = config.i18n[type];
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case 'pip':
|
||||||
|
text = 'PIP';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'airplay':
|
||||||
|
text = 'AirPlay';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return createElement('span', {
|
||||||
class: config.classes.hidden
|
class: config.classes.hidden
|
||||||
});
|
}, text);
|
||||||
|
|
||||||
var text = document.createTextNode(config.i18n[type]);
|
|
||||||
|
|
||||||
label.appendChild(text);
|
|
||||||
|
|
||||||
return label;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a <button>
|
// Create a <button>
|
||||||
@ -964,23 +1038,58 @@
|
|||||||
var button = createElement('button');
|
var button = createElement('button');
|
||||||
var attributes = {
|
var attributes = {
|
||||||
class: 'plyr__control'
|
class: 'plyr__control'
|
||||||
}
|
};
|
||||||
|
var iconDefault;
|
||||||
|
var iconToggled;
|
||||||
|
var labelKey;
|
||||||
|
|
||||||
// Large play button
|
// Large play button
|
||||||
// TODO: use config
|
switch (type) {
|
||||||
if (type === 'play-large') {
|
case 'mute':
|
||||||
attributes.class = 'plyr__play-large';
|
labelKey = 'toggleMute';
|
||||||
type = 'play';
|
iconDefault = 'volume';
|
||||||
|
iconToggled = 'muted';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'captions':
|
||||||
|
labelKey = 'toggleCaptions';
|
||||||
|
iconDefault = 'captions-off';
|
||||||
|
iconToggled = 'captions-on';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'fullscreen':
|
||||||
|
labelKey = 'toggleFullscreen';
|
||||||
|
iconDefault = 'enter-fullscreen';
|
||||||
|
iconToggled = 'exit-fullscreen';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'play-large':
|
||||||
|
attributes.class = 'plyr__play-large';
|
||||||
|
type = 'play';
|
||||||
|
labelKey = 'play';
|
||||||
|
iconDefault = 'play';
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
labelKey = type;
|
||||||
|
iconDefault = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge attributes
|
// Merge attributes
|
||||||
extend(attributes, getAttributesFromSelector(config.selectors.buttons[type], attributes));
|
extend(attributes, getAttributesFromSelector(config.selectors.buttons[type], attributes));
|
||||||
|
|
||||||
|
// Add toggle icon if needed
|
||||||
|
if (is.string(iconToggled)) {
|
||||||
|
button.appendChild(createIcon(iconToggled, {
|
||||||
|
class: 'icon--' + iconToggled
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
// Add the icon
|
// Add the icon
|
||||||
button.appendChild(createIcon(type));
|
button.appendChild(createIcon(iconDefault));
|
||||||
|
|
||||||
// Add the label
|
// Add the label
|
||||||
button.appendChild(createLabel(type));
|
button.appendChild(createLabel(labelKey));
|
||||||
|
|
||||||
// Set element attributes
|
// Set element attributes
|
||||||
setAttributes(button, attributes);
|
setAttributes(button, attributes);
|
||||||
@ -990,39 +1099,81 @@
|
|||||||
return button;
|
return button;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create an <input type='range'>
|
||||||
|
function createRange(type, attributes) {
|
||||||
|
var id = 'plyr-' + type + (is.object(attributes) && 'id' in attributes ? '-' + attributes.id : '');
|
||||||
|
|
||||||
|
// Seek label
|
||||||
|
var label = createElement('label', {
|
||||||
|
for: id,
|
||||||
|
class: config.classes.hidden
|
||||||
|
}, config.i18n[type]);
|
||||||
|
|
||||||
|
// Seek input
|
||||||
|
var input = createElement('input', extend(getAttributesFromSelector(config.selectors.inputs[type]), {
|
||||||
|
id: id,
|
||||||
|
type: 'range',
|
||||||
|
min: 0,
|
||||||
|
max: 100,
|
||||||
|
step: 0.1,
|
||||||
|
value: 0
|
||||||
|
}, attributes));
|
||||||
|
|
||||||
|
elements.inputs[type] = input;
|
||||||
|
|
||||||
|
return {
|
||||||
|
label: label,
|
||||||
|
input: input
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create a <progress>
|
// Create a <progress>
|
||||||
function createProgress(type) {
|
function createProgress(type, attributes) {
|
||||||
var progress = createElement('progress', extend(getAttributesFromSelector(config.selectors.progress[type]), {
|
var progress = createElement('progress', extend(getAttributesFromSelector(config.selectors.display[type]), {
|
||||||
min: 0,
|
min: 0,
|
||||||
max: 100,
|
max: 100,
|
||||||
value: 0
|
value: 0
|
||||||
}));
|
}, attributes));
|
||||||
|
|
||||||
// Create the label inside
|
// Create the label inside
|
||||||
var value = createElement('span');
|
if (type !== 'volume') {
|
||||||
var text = document.createTextNode('0');
|
progress.appendChild(createElement('span', null, '0'));
|
||||||
value.appendChild(text);
|
|
||||||
progress.appendChild(value);
|
|
||||||
|
|
||||||
var suffix = '';
|
var suffix = '';
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'played':
|
case 'played':
|
||||||
suffix = config.i18n.played;
|
suffix = config.i18n.played;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'buffer':
|
case 'buffer':
|
||||||
suffix = config.i18n.buffered;
|
suffix = config.i18n.buffered;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var label = document.createTextNode('% ' + suffix.toLowerCase());
|
||||||
|
progress.appendChild(label);
|
||||||
}
|
}
|
||||||
|
|
||||||
var label = document.createTextNode('% ' + suffix.toLowerCase());
|
elements.display[type] = progress;
|
||||||
progress.appendChild(label);
|
|
||||||
|
|
||||||
elements.progress[type] = [progress];
|
|
||||||
|
|
||||||
return progress;
|
return progress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create time display
|
||||||
|
function createTime(type) {
|
||||||
|
var container = createElement('span', {
|
||||||
|
class: 'plyr__time'
|
||||||
|
});
|
||||||
|
|
||||||
|
container.appendChild(createElement('span', {
|
||||||
|
class: config.classes.hidden
|
||||||
|
}, config.i18n[type]));
|
||||||
|
|
||||||
|
container.appendChild(createElement('span', getAttributesFromSelector(config.selectors.display[type]), '00:00'));
|
||||||
|
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
|
||||||
// Build the default HTML
|
// Build the default HTML
|
||||||
function createControls(data) {
|
function createControls(data) {
|
||||||
// Create the container
|
// Create the container
|
||||||
@ -1052,56 +1203,23 @@
|
|||||||
|
|
||||||
// Progress
|
// Progress
|
||||||
if (inArray(config.controls, 'progress')) {
|
if (inArray(config.controls, 'progress')) {
|
||||||
var container = createElement('span', getAttributesFromSelector(config.selectors.progress.container));
|
var container = createElement('span', getAttributesFromSelector(config.selectors.progress));
|
||||||
|
|
||||||
|
// Seek range slider
|
||||||
|
var seek = createRange('seek', {
|
||||||
|
id: data.id
|
||||||
|
});
|
||||||
|
container.appendChild(seek.label);
|
||||||
|
container.appendChild(seek.input);
|
||||||
|
|
||||||
// TODO: Add loop display indicator
|
// TODO: Add loop display indicator
|
||||||
|
|
||||||
// Seeking
|
// Played progress
|
||||||
var seek = {
|
|
||||||
id: "seek-" + data.id,
|
|
||||||
label: createElement('label'),
|
|
||||||
input: createElement('input')
|
|
||||||
};
|
|
||||||
|
|
||||||
// Seek label
|
|
||||||
setAttributes(seek.label, {
|
|
||||||
for: seek.id,
|
|
||||||
class: config.classes.hidden
|
|
||||||
});
|
|
||||||
container.appendChild(seek.label);
|
|
||||||
|
|
||||||
// Seek input
|
|
||||||
setAttributes(seek.input, extend(getAttributesFromSelector(config.selectors.inputs.seek), {
|
|
||||||
id: seek.id,
|
|
||||||
type: 'range',
|
|
||||||
min: 0,
|
|
||||||
max: 100,
|
|
||||||
step: 0.1,
|
|
||||||
value: 0
|
|
||||||
}));
|
|
||||||
extend(elements.inputs, {
|
|
||||||
seek: seek.input
|
|
||||||
});
|
|
||||||
container.appendChild(elements.inputs.seek);
|
|
||||||
|
|
||||||
container.appendChild(createProgress('played'));
|
container.appendChild(createProgress('played'));
|
||||||
|
|
||||||
|
// Buffer progress
|
||||||
container.appendChild(createProgress('buffer'));
|
container.appendChild(createProgress('buffer'));
|
||||||
|
|
||||||
// Create progress
|
|
||||||
/* beautify ignore:start */
|
|
||||||
/*html.push(
|
|
||||||
'<span class="plyr__progress">',
|
|
||||||
//'<div class="plyr__progress-loop"></div>',
|
|
||||||
'<label for="seek-{id}" class="plyr__sr-only">Seek</label>',
|
|
||||||
'<input id="seek-{id}" class="plyr__progress--seek" type="range" min="0" max="100" step="0.1" value="0" data-plyr="seek">',
|
|
||||||
'<progress class="plyr__progress--played" max="100" value="0" role="presentation"></progress>',
|
|
||||||
'<progress class="plyr__progress--buffer" max="100" value="0">',
|
|
||||||
'<span>0</span>% ' + config.i18n.buffered,
|
|
||||||
'</progress>'
|
|
||||||
);&/
|
|
||||||
/* beautify ignore:end */
|
|
||||||
|
|
||||||
// Seek tooltip
|
// Seek tooltip
|
||||||
if (config.tooltips.seek) {
|
if (config.tooltips.seek) {
|
||||||
//html.push('<span class="plyr__tooltip">00:00</span>');
|
//html.push('<span class="plyr__tooltip">00:00</span>');
|
||||||
@ -1115,80 +1233,58 @@
|
|||||||
container.appendChild(tooltip);
|
container.appendChild(tooltip);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close
|
elements.progress = container;
|
||||||
//html.push('</span>');
|
controls.appendChild(elements.progress);
|
||||||
elements.progress.container = container;
|
|
||||||
controls.appendChild(elements.progress.container);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return controls;
|
|
||||||
|
|
||||||
// Media current time display
|
// Media current time display
|
||||||
if (inArray(config.controls, 'current-time')) {
|
if (inArray(config.controls, 'current-time')) {
|
||||||
/* beautify ignore:start */
|
controls.appendChild(createTime('currentTime'));
|
||||||
html.push(
|
|
||||||
'<span class="plyr__time">',
|
|
||||||
'<span class="plyr__sr-only">' + config.i18n.currentTime + '</span>',
|
|
||||||
'<span class="plyr__time--current">00:00</span>',
|
|
||||||
'</span>'
|
|
||||||
);
|
|
||||||
/* beautify ignore:end */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Media duration display
|
// Media duration display
|
||||||
if (inArray(config.controls, 'duration')) {
|
if (inArray(config.controls, 'duration')) {
|
||||||
/* beautify ignore:start */
|
controls.appendChild(createTime('duration'));
|
||||||
html.push(
|
|
||||||
'<span class="plyr__time">',
|
|
||||||
'<span class="plyr__sr-only">' + config.i18n.duration + '</span>',
|
|
||||||
'<span class="plyr__time--duration">00:00</span>',
|
|
||||||
'</span>'
|
|
||||||
);
|
|
||||||
/* beautify ignore:end */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Toggle mute button
|
// Toggle mute button
|
||||||
if (inArray(config.controls, 'mute')) {
|
if (inArray(config.controls, 'mute')) {
|
||||||
/* beautify ignore:start */
|
controls.appendChild(createButton('mute'));
|
||||||
html.push(
|
|
||||||
'<button type="button" class="plyr__control" data-plyr="mute">',
|
|
||||||
'<svg class="icon--muted"><use xlink:href="' + iconPath + '-muted" /></svg>',
|
|
||||||
'<svg><use xlink:href="' + iconPath + '-volume" /></svg>',
|
|
||||||
'<span class="plyr__sr-only">' + config.i18n.toggleMute + '</span>',
|
|
||||||
'</button>'
|
|
||||||
);
|
|
||||||
/* beautify ignore:end */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Volume range control
|
// Volume range control
|
||||||
if (inArray(config.controls, 'volume')) {
|
if (inArray(config.controls, 'volume')) {
|
||||||
/* beautify ignore:start */
|
var volume = createElement('span', {
|
||||||
html.push(
|
class: 'plyr__volume'
|
||||||
'<span class="plyr__volume">',
|
});
|
||||||
'<label for="volume-{id}" class="plyr__sr-only">' + config.i18n.volume + '</label>',
|
|
||||||
'<input id="volume-{id}" class="plyr__volume--input" type="range" min="' + 0 + '" max="' + 10 + '" value="' + config.volume + '" data-plyr="volume">',
|
// Set the attributes
|
||||||
'<progress class="plyr__volume--display" max="' + 10 + '" value="' + 0 + '" role="presentation"></progress>',
|
var attributes = {
|
||||||
'</span>'
|
id: data.id,
|
||||||
);
|
max: 10,
|
||||||
/* beautify ignore:end */
|
value: config.volume
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create the volume range slider
|
||||||
|
var range = createRange('volume', attributes);
|
||||||
|
volume.appendChild(range.label);
|
||||||
|
volume.appendChild(range.input);
|
||||||
|
|
||||||
|
// Create the display progress
|
||||||
|
var progress = createProgress('volume', attributes);
|
||||||
|
volume.appendChild(progress);
|
||||||
|
|
||||||
|
controls.appendChild(volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Toggle captions button
|
// Toggle captions button
|
||||||
if (inArray(config.controls, 'captions')) {
|
if (inArray(config.controls, 'captions')) {
|
||||||
/* beautify ignore:start */
|
controls.appendChild(createButton('captions'));
|
||||||
html.push(
|
|
||||||
'<button type="button" class="plyr__control" data-plyr="captions">',
|
|
||||||
'<svg class="icon--captions-on"><use xlink:href="' + iconPath + '-captions-on" /></svg>',
|
|
||||||
'<svg><use xlink:href="' + iconPath + '-captions-off" /></svg>',
|
|
||||||
'<span class="plyr__sr-only">' + config.i18n.toggleCaptions + '</span>',
|
|
||||||
'</button>'
|
|
||||||
);
|
|
||||||
/* beautify ignore:end */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Settings button / menu
|
// Settings button / menu
|
||||||
if (inArray(config.controls, 'settings')) {
|
if (inArray(config.controls, 'settings')) {
|
||||||
/* beautify ignore:start */
|
/*
|
||||||
var captionsMenuItem = '';
|
var captionsMenuItem = '';
|
||||||
if (inArray(config.controls, 'captions')) {
|
if (inArray(config.controls, 'captions')) {
|
||||||
captionsMenuItem = '<li role="tab">'+
|
captionsMenuItem = '<li role="tab">'+
|
||||||
@ -1380,51 +1476,25 @@
|
|||||||
'</div>',
|
'</div>',
|
||||||
'</form>',
|
'</form>',
|
||||||
'</div>'
|
'</div>'
|
||||||
);
|
); */
|
||||||
/* beautify ignore:end */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Picture in picture button
|
// Picture in picture button
|
||||||
if (inArray(config.controls, 'pip') && support.pip) {
|
if (inArray(config.controls, 'pip') && support.pip) {
|
||||||
/* beautify ignore:start */
|
controls.appendChild(createButton('pip'));
|
||||||
html.push(
|
|
||||||
'<button type="button" class="plyr__control" data-plyr="pip">',
|
|
||||||
'<svg><use xlink:href="' + iconPath + '-pip" /></svg>',
|
|
||||||
'<span class="plyr__sr-only">PIP</span>',
|
|
||||||
'</button>'
|
|
||||||
);
|
|
||||||
/* beautify ignore:end */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Airplay button
|
// Airplay button
|
||||||
if (inArray(config.controls, 'airplay') && support.airplay) {
|
if (inArray(config.controls, 'airplay') && support.airplay) {
|
||||||
/* beautify ignore:start */
|
controls.appendChild(createButton('airplay'));
|
||||||
html.push(
|
|
||||||
'<button type="button" class="plyr__control" data-plyr="airplay">',
|
|
||||||
'<svg><use xlink:href="' + iconPath + '-airplay" /></svg>',
|
|
||||||
'<span class="plyr__sr-only">AirPlay</span>',
|
|
||||||
'</button>'
|
|
||||||
);
|
|
||||||
/* beautify ignore:end */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Toggle fullscreen button
|
// Toggle fullscreen button
|
||||||
if (inArray(config.controls, 'fullscreen')) {
|
if (inArray(config.controls, 'fullscreen')) {
|
||||||
/* beautify ignore:start */
|
controls.appendChild(createButton('fullscreen'));
|
||||||
html.push(
|
|
||||||
'<button type="button" class="plyr__control" data-plyr="fullscreen">',
|
|
||||||
'<svg class="icon--exit-fullscreen"><use xlink:href="' + iconPath + '-exit-fullscreen" /></svg>',
|
|
||||||
'<svg><use xlink:href="' + iconPath + '-enter-fullscreen" /></svg>',
|
|
||||||
'<span class="plyr__sr-only">' + config.i18n.toggleFullscreen + '</span>',
|
|
||||||
'</button>'
|
|
||||||
);
|
|
||||||
/* beautify ignore:end */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close everything
|
return controls;
|
||||||
html.push('</div>');
|
|
||||||
|
|
||||||
return html.join('');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the YouTube quality menu
|
// Set the YouTube quality menu
|
||||||
@ -1714,6 +1784,33 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Select active caption
|
||||||
|
function setCaptionIndex(index) {
|
||||||
|
// Save active caption
|
||||||
|
config.captions.selectedIndex = index || config.captions.selectedIndex;
|
||||||
|
|
||||||
|
// Clear caption
|
||||||
|
setCaption();
|
||||||
|
|
||||||
|
// Re-run setup
|
||||||
|
setupCaptions();
|
||||||
|
|
||||||
|
//getElement('[data-captions="settings"]').innerHTML = getSelectedLanguage();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get current selected caption language
|
||||||
|
function getSelectedLanguage() {
|
||||||
|
if (config.tracks.length === 0) {
|
||||||
|
return 'No Subs';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (plyr.captionsEnabled || !is.boolean(plyr.captionsEnabled) && plyr.storage.captionsEnabled) {
|
||||||
|
return config.tracks[config.captions.selectedIndex].label;
|
||||||
|
} else {
|
||||||
|
return 'Disabled';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Set the current caption
|
// Set the current caption
|
||||||
function setCaption(caption) {
|
function setCaption(caption) {
|
||||||
var captions = getElement(config.selectors.captions);
|
var captions = getElement(config.selectors.captions);
|
||||||
@ -1846,61 +1943,36 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find all elements
|
// Toggle captions
|
||||||
function getElements(selector) {
|
function toggleCaptions(show) {
|
||||||
return plyr.container.querySelectorAll(selector);
|
// If there's no full support, or there's no caption toggle
|
||||||
}
|
if (!plyr.supported.full || !elements.buttons.captions) {
|
||||||
|
return;
|
||||||
// Find a single element
|
|
||||||
function getElement(selector) {
|
|
||||||
return getElements(selector)[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine if we're in an iframe
|
|
||||||
function inFrame() {
|
|
||||||
try {
|
|
||||||
return window.self !== window.top;
|
|
||||||
} catch (e) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Trap focus inside container
|
|
||||||
function focusTrap() {
|
|
||||||
var tabbables = getElements('input:not([disabled]), button:not([disabled])'),
|
|
||||||
first = tabbables[0],
|
|
||||||
last = tabbables[tabbables.length - 1];
|
|
||||||
|
|
||||||
function checkFocus(event) {
|
|
||||||
// If it is TAB
|
|
||||||
if (event.which === 9 && plyr.isFullscreen) {
|
|
||||||
if (event.target === last && !event.shiftKey) {
|
|
||||||
// Move focus to first element that can be tabbed if Shift isn't used
|
|
||||||
event.preventDefault();
|
|
||||||
first.focus();
|
|
||||||
} else if (event.target === first && event.shiftKey) {
|
|
||||||
// Move focus to last element that can be tabbed if Shift is used
|
|
||||||
event.preventDefault();
|
|
||||||
last.focus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bind the handler
|
// If the method is called without parameter, toggle based on current value
|
||||||
on(plyr.container, 'keydown', checkFocus);
|
if (!is.boolean(show)) {
|
||||||
}
|
show = (plyr.container.className.indexOf(config.classes.captions.active) === -1);
|
||||||
|
|
||||||
// Add elements to HTML5 media (source, tracks, etc)
|
|
||||||
function insertChildElements(type, attributes) {
|
|
||||||
if (is.string(attributes)) {
|
|
||||||
insertElement(type, plyr.media, {
|
|
||||||
src: attributes
|
|
||||||
});
|
|
||||||
} else if (attributes.constructor === Array) {
|
|
||||||
for (var i = attributes.length - 1; i >= 0; i--) {
|
|
||||||
insertElement(type, plyr.media, attributes[i]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set global
|
||||||
|
plyr.captionsEnabled = show;
|
||||||
|
elements.buttons.captions_menu.innerHTML = show ? 'Off' : 'On';
|
||||||
|
getElement('[data-captions="settings"]').innerHTML = getSubsLangValue();
|
||||||
|
|
||||||
|
// Toggle state
|
||||||
|
toggleState(elements.buttons.captions, plyr.captionsEnabled);
|
||||||
|
|
||||||
|
// Add class hook
|
||||||
|
toggleClass(plyr.container, config.classes.captions.active, plyr.captionsEnabled);
|
||||||
|
|
||||||
|
// Trigger an event
|
||||||
|
trigger(plyr.container, plyr.captionsEnabled ? 'captionsenabled' : 'captionsdisabled', true);
|
||||||
|
|
||||||
|
// Save captions state to localStorage
|
||||||
|
updateStorage({
|
||||||
|
captionsEnabled: plyr.captionsEnabled
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert controls
|
// Insert controls
|
||||||
@ -1966,10 +2038,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSpeedDisplayValue() {
|
|
||||||
return config.currentSpeed.toFixed(1).toString().replace('.0', '') + '×'
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the UI controls and store references
|
// Find the UI controls and store references
|
||||||
function findElements() {
|
function findElements() {
|
||||||
try {
|
try {
|
||||||
@ -1992,22 +2060,8 @@
|
|||||||
captions: getElement(config.selectors.buttons.captions)
|
captions: getElement(config.selectors.buttons.captions)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Inputs
|
|
||||||
// TODO: ??
|
|
||||||
// elements.buttons.captions_menu = getElement(config.selectors.buttons.captions_menu);
|
|
||||||
|
|
||||||
// Progress
|
// Progress
|
||||||
// TODO: text for played?
|
elements.progress = getElement(config.selectors.progress);
|
||||||
elements.progress = {
|
|
||||||
container: getElement(config.selectors.progress.container),
|
|
||||||
buffer: getElement(config.selectors.progress.buffer),
|
|
||||||
played: getElement(config.selectors.progress.played)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Seek tooltip
|
|
||||||
if (is.htmlElement(elements.progress.container)) {
|
|
||||||
elements.progress.tooltip = elements.progress.container.querySelector('.' + config.classes.tooltip);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Inputs
|
// Inputs
|
||||||
elements.inputs = {
|
elements.inputs = {
|
||||||
@ -2017,11 +2071,18 @@
|
|||||||
|
|
||||||
// Display
|
// Display
|
||||||
elements.display = {
|
elements.display = {
|
||||||
|
buffer: getElement(config.selectors.display.buffer),
|
||||||
|
played: getElement(config.selectors.display.played),
|
||||||
volume: getElement(config.selectors.display.volume),
|
volume: getElement(config.selectors.display.volume),
|
||||||
duration: getElement(config.selectors.display.duration),
|
duration: getElement(config.selectors.display.duration),
|
||||||
currentTime: getElement(config.selectors.display.currentTime),
|
currentTime: getElement(config.selectors.display.currentTime),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Seek tooltip
|
||||||
|
if (is.htmlElement(elements.progress)) {
|
||||||
|
elements.display.seekTooltip = elements.progress.querySelector('.' + config.classes.tooltip);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
warn('It looks like there is a problem with your custom controls HTML', error);
|
warn('It looks like there is a problem with your custom controls HTML', error);
|
||||||
@ -2697,7 +2758,7 @@
|
|||||||
config.loop.end = null;
|
config.loop.end = null;
|
||||||
}
|
}
|
||||||
config.loop.start = currentTime;
|
config.loop.start = currentTime;
|
||||||
config.loop.indicator.start = elements.progress.played.value;
|
config.loop.indicator.start = elements.display.played.value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'end':
|
case 'end':
|
||||||
@ -2705,7 +2766,7 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
config.loop.end = currentTime;
|
config.loop.end = currentTime;
|
||||||
config.loop.indicator.end = elements.progress.played.value;
|
config.loop.indicator.end = elements.display.played.value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'all':
|
case 'all':
|
||||||
@ -2797,8 +2858,13 @@
|
|||||||
speed: speed
|
speed: speed
|
||||||
});
|
});
|
||||||
|
|
||||||
//Update current value of menu
|
// Update current value of menu
|
||||||
document.querySelector('[data-menu="speed"]').innerHTML = getSpeedDisplayValue();
|
// document.querySelector('[data-menu="speed"]').innerHTML = getSpeedDisplayValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the current speed value
|
||||||
|
function getSpeedDisplayValue() {
|
||||||
|
return config.currentSpeed.toFixed(1).toString().replace('.0', '') + '×'
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rewind
|
// Rewind
|
||||||
@ -3127,64 +3193,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Toggle captions
|
|
||||||
function toggleCaptions(show) {
|
|
||||||
// If there's no full support, or there's no caption toggle
|
|
||||||
if (!plyr.supported.full || !elements.buttons.captions) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the method is called without parameter, toggle based on current value
|
|
||||||
if (!is.boolean(show)) {
|
|
||||||
show = (plyr.container.className.indexOf(config.classes.captions.active) === -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set global
|
|
||||||
plyr.captionsEnabled = show;
|
|
||||||
elements.buttons.captions_menu.innerHTML = show ? 'Off' : 'On';
|
|
||||||
getElement('[data-captions="settings"]').innerHTML = getSubsLangValue();
|
|
||||||
|
|
||||||
// Toggle state
|
|
||||||
toggleState(elements.buttons.captions, plyr.captionsEnabled);
|
|
||||||
|
|
||||||
// Add class hook
|
|
||||||
toggleClass(plyr.container, config.classes.captions.active, plyr.captionsEnabled);
|
|
||||||
|
|
||||||
// Trigger an event
|
|
||||||
trigger(plyr.container, plyr.captionsEnabled ? 'captionsenabled' : 'captionsdisabled', true);
|
|
||||||
|
|
||||||
// Save captions state to localStorage
|
|
||||||
updateStorage({
|
|
||||||
captionsEnabled: plyr.captionsEnabled
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Select active caption
|
|
||||||
function setCaptionIndex(index) {
|
|
||||||
// Save active caption
|
|
||||||
config.captions.selectedIndex = index || config.captions.selectedIndex;
|
|
||||||
|
|
||||||
// Clear caption
|
|
||||||
setCaption();
|
|
||||||
|
|
||||||
// Re-run setup
|
|
||||||
setupCaptions();
|
|
||||||
|
|
||||||
getElement('[data-captions="settings"]').innerHTML = getSubsLangValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
function getSubsLangValue() {
|
|
||||||
if (config.tracks.length === 0) {
|
|
||||||
return 'No Subs';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (plyr.captionsEnabled || !is.boolean(plyr.captionsEnabled) && plyr.storage.captionsEnabled) {
|
|
||||||
return config.tracks[config.captions.selectedIndex].label;
|
|
||||||
} else {
|
|
||||||
return 'Disabled';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if media is loading
|
// Check if media is loading
|
||||||
function checkLoading(event) {
|
function checkLoading(event) {
|
||||||
var loading = (event.type === 'waiting');
|
var loading = (event.type === 'waiting');
|
||||||
@ -3208,7 +3216,7 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var progress = elements.progress.played,
|
var progress = elements.display.played,
|
||||||
value = 0,
|
value = 0,
|
||||||
duration = getDuration();
|
duration = getDuration();
|
||||||
|
|
||||||
@ -3233,7 +3241,7 @@
|
|||||||
// Check buffer status
|
// Check buffer status
|
||||||
case 'playing':
|
case 'playing':
|
||||||
case 'progress':
|
case 'progress':
|
||||||
progress = elements.progress.buffer;
|
progress = elements.display.buffer;
|
||||||
value = (function() {
|
value = (function() {
|
||||||
var buffered = plyr.media.buffered;
|
var buffered = plyr.media.buffered;
|
||||||
|
|
||||||
@ -3271,8 +3279,8 @@
|
|||||||
}
|
}
|
||||||
// Default to buffer or bail
|
// Default to buffer or bail
|
||||||
if (is.undefined(progress)) {
|
if (is.undefined(progress)) {
|
||||||
if (is.htmlElement(elements.progress.buffer)) {
|
if (is.htmlElement(elements.display.buffer)) {
|
||||||
progress = elements.progress.buffer;
|
progress = elements.display.buffer;
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -3371,8 +3379,8 @@
|
|||||||
value = getPercentage(time, duration);
|
value = getPercentage(time, duration);
|
||||||
|
|
||||||
// Update progress
|
// Update progress
|
||||||
if (elements.progress && elements.progress.played) {
|
if (elements.progress && elements.display.played) {
|
||||||
elements.progress.played.value = value;
|
elements.display.played.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update seek range input
|
// Update seek range input
|
||||||
@ -3397,8 +3405,8 @@
|
|||||||
|
|
||||||
// Determine percentage, if already visible
|
// Determine percentage, if already visible
|
||||||
if (!event) {
|
if (!event) {
|
||||||
if (hasClass(elements.progress.tooltip, visible)) {
|
if (hasClass(elements.display.seekTooltip, visible)) {
|
||||||
percent = elements.progress.tooltip.style.left.replace('%', '');
|
percent = elements.display.seekTooltip.style.left.replace('%', '');
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -3414,15 +3422,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Display the time a click would seek to
|
// Display the time a click would seek to
|
||||||
updateTimeDisplay(((duration / 100) * percent), elements.progress.tooltip);
|
updateTimeDisplay(((duration / 100) * percent), elements.display.seekTooltip);
|
||||||
|
|
||||||
// Set position
|
// Set position
|
||||||
elements.progress.tooltip.style.left = percent + "%";
|
elements.display.seekTooltip.style.left = percent + "%";
|
||||||
|
|
||||||
// Show/hide the tooltip
|
// Show/hide the tooltip
|
||||||
// If the event is a moues in/out and percentage is inside bounds
|
// If the event is a moues in/out and percentage is inside bounds
|
||||||
if (event && inArray(['mouseenter', 'mouseleave'], event.type)) {
|
if (event && inArray(['mouseenter', 'mouseleave'], event.type)) {
|
||||||
toggleClass(elements.progress.tooltip, visible, (event.type === 'mouseenter'));
|
toggleClass(elements.display.seekTooltip, visible, (event.type === 'mouseenter'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3635,7 +3643,7 @@
|
|||||||
|
|
||||||
// Set new sources for html5
|
// Set new sources for html5
|
||||||
if (inArray(config.types.html5, plyr.type)) {
|
if (inArray(config.types.html5, plyr.type)) {
|
||||||
insertChildElements('source', source.sources);
|
insertElements('source', source.sources);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up from scratch
|
// Set up from scratch
|
||||||
@ -3645,7 +3653,7 @@
|
|||||||
if (inArray(config.types.html5, plyr.type)) {
|
if (inArray(config.types.html5, plyr.type)) {
|
||||||
// Setup captions
|
// Setup captions
|
||||||
if ('tracks' in source) {
|
if ('tracks' in source) {
|
||||||
insertChildElements('track', source.tracks);
|
insertElements('track', source.tracks);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load HTML5 sources
|
// Load HTML5 sources
|
||||||
@ -3946,8 +3954,8 @@
|
|||||||
|
|
||||||
// Speed-up
|
// Speed-up
|
||||||
proxy(elements.buttons.speed, 'click', config.listeners.speed, function() {
|
proxy(elements.buttons.speed, 'click', config.listeners.speed, function() {
|
||||||
var speedValue = document.querySelector('[data-plyr="speed"]:checked').value;
|
//var speedValue = document.querySelector('[data-plyr="speed"]:checked').value;
|
||||||
setSpeed(Number(speedValue));
|
//setSpeed(Number(speedValue));
|
||||||
});
|
});
|
||||||
|
|
||||||
// Seek
|
// Seek
|
||||||
|
Loading…
x
Reference in New Issue
Block a user