WIP
This commit is contained in:
parent
7c6d4666e9
commit
38f10d4cc6
20
controls.md
20
controls.md
@ -2,9 +2,9 @@
|
||||
|
||||
This is the markup that is rendered for the Plyr controls. You can use the default controls or provide a customized version of markup based on your needs. You can pass the following to the `controls` option:
|
||||
|
||||
* `Array` of options (this builds the default controls based on your choices)
|
||||
* `String` containing the desired HTML
|
||||
* `Function` that will be executed and should return one of the above
|
||||
- `Array` of options (this builds the default controls based on your choices)
|
||||
- `String` containing the desired HTML
|
||||
- `Function` that will be executed and should return one of the above
|
||||
|
||||
## Using default controls
|
||||
|
||||
@ -81,14 +81,14 @@ The classes and data attributes used in your template should match the `selector
|
||||
|
||||
You need to add several placeholders to your HTML template that are replaced when rendering:
|
||||
|
||||
* `{id}` - the dynamically generated ID for the player (for form controls)
|
||||
* `{seektime}` - the seek time specified in options for fast forward and rewind
|
||||
* `{title}` - the title of your media, if specified
|
||||
- `{id}` - the dynamically generated ID for the player (for form controls)
|
||||
- `{seektime}` - the seek time specified in options for fast forward and rewind
|
||||
- `{title}` - the title of your media, if specified
|
||||
|
||||
### Limitations
|
||||
|
||||
* Currently the settings menus are not supported with custom controls HTML
|
||||
* AirPlay and PiP buttons can be added but you will have to manage feature detection
|
||||
- Currently the settings menus are not supported with custom controls HTML
|
||||
- AirPlay and PiP buttons can be added but you will have to manage feature detection
|
||||
|
||||
### Example
|
||||
|
||||
@ -131,13 +131,13 @@ const controls = `
|
||||
<div class="plyr__volume">
|
||||
<input data-plyr="volume" type="range" min="0" max="1" step="0.05" value="1" autocomplete="off" aria-label="Volume">
|
||||
</div>
|
||||
<button type="button" class="plyr__control" aria-label="Enable captions" data-plyr="captions">
|
||||
<button type="button" class="plyr__control" data-plyr="captions">
|
||||
<svg class="icon--pressed" role="presentation"><use xlink:href="#plyr-captions-on"></use></svg>
|
||||
<svg class="icon--not-pressed" role="presentation"><use xlink:href="#plyr-captions-off"></use></svg>
|
||||
<span class="label--pressed plyr__tooltip" role="tooltip">Disable captions</span>
|
||||
<span class="label--not-pressed plyr__tooltip" role="tooltip">Enable captions</span>
|
||||
</button>
|
||||
<button type="button" class="plyr__control" aria-label="Enter fullscreen" data-plyr="fullscreen">
|
||||
<button type="button" class="plyr__control" data-plyr="fullscreen">
|
||||
<svg class="icon--pressed" role="presentation"><use xlink:href="#plyr-exit-fullscreen"></use></svg>
|
||||
<svg class="icon--not-pressed" role="presentation"><use xlink:href="#plyr-enter-fullscreen"></use></svg>
|
||||
<span class="label--pressed plyr__tooltip" role="tooltip">Exit fullscreen</span>
|
||||
|
53
dist/plyr.js
vendored
53
dist/plyr.js
vendored
@ -1789,7 +1789,6 @@ var i18n = {
|
||||
var browser = utils.getBrowser();
|
||||
|
||||
var controls = {
|
||||
|
||||
// Get icon URL
|
||||
getIconUrl: function getIconUrl() {
|
||||
var url = new URL(this.config.iconUrl, window.location);
|
||||
@ -2168,6 +2167,23 @@ var controls = {
|
||||
},
|
||||
|
||||
|
||||
// Format a time for display
|
||||
formatTime: function formatTime() {
|
||||
var time = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
|
||||
var inverted = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
||||
|
||||
// Bail if the value isn't a number
|
||||
if (!utils.is.number(time)) {
|
||||
return time;
|
||||
}
|
||||
|
||||
// Always display hours if duration is over an hour
|
||||
var forceHours = utils.getHours(this.duration) > 0;
|
||||
|
||||
return utils.formatTime(time, forceHours, inverted);
|
||||
},
|
||||
|
||||
|
||||
// Update the displayed time
|
||||
updateTimeDisplay: function updateTimeDisplay() {
|
||||
var target = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
|
||||
@ -2179,11 +2195,8 @@ var controls = {
|
||||
return;
|
||||
}
|
||||
|
||||
// Always display hours if duration is over an hour
|
||||
var forceHours = utils.getHours(this.duration) > 0;
|
||||
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
target.innerText = utils.formatTime(time, forceHours, inverted);
|
||||
target.innerText = controls.formatTime(time, inverted);
|
||||
},
|
||||
|
||||
|
||||
@ -2286,8 +2299,20 @@ var controls = {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set aria value for https://github.com/sampotts/plyr/issues/905
|
||||
// Set aria values for https://github.com/sampotts/plyr/issues/905
|
||||
if (utils.matches(range, this.config.selectors.inputs.seek)) {
|
||||
range.setAttribute('aria-valuenow', this.currentTime);
|
||||
var currentTime = controls.formatTime(this.currentTime);
|
||||
var duration = controls.formatTime(this.duration);
|
||||
var format = i18n.get('seekLabel', this.config);
|
||||
range.setAttribute('aria-valuetext', format.replace('{currentTime}', currentTime).replace('{duration}', duration));
|
||||
} else if (utils.matches(range, this.config.selectors.inputs.volume)) {
|
||||
var percent = range.value * 100;
|
||||
range.setAttribute('aria-valuenow', percent);
|
||||
range.setAttribute('aria-valuetext', percent + '%');
|
||||
} else {
|
||||
range.setAttribute('aria-valuenow', range.value);
|
||||
}
|
||||
|
||||
// WebKit only
|
||||
if (!browser.isWebkit) {
|
||||
@ -2373,11 +2398,16 @@ var controls = {
|
||||
|
||||
// Show the duration on metadataloaded or durationchange events
|
||||
durationUpdate: function durationUpdate() {
|
||||
// Bail if no ui or durationchange event triggered after playing/seek when invertTime is false
|
||||
// Bail if no UI or durationchange event triggered after playing/seek when invertTime is false
|
||||
if (!this.supported.ui || !this.config.invertTime && this.currentTime) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update ARIA values
|
||||
if (utils.is.element(this.elements.inputs.seek)) {
|
||||
this.elements.inputs.seek.setAttribute('aria-valuemax', this.duration);
|
||||
}
|
||||
|
||||
// If there's a spot to display duration
|
||||
var hasDuration = utils.is.element(this.elements.display.duration);
|
||||
|
||||
@ -3218,7 +3248,6 @@ var controls = {
|
||||
Array.from(labels).forEach(function (label) {
|
||||
utils.toggleClass(label, _this7.config.classNames.hidden, false);
|
||||
utils.toggleClass(label, _this7.config.classNames.tooltip, true);
|
||||
label.setAttribute('role', 'tooltip');
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -3659,6 +3688,7 @@ var defaults$1 = {
|
||||
pause: 'Pause',
|
||||
fastForward: 'Forward {seektime}s',
|
||||
seek: 'Seek',
|
||||
seekLabel: '{currentTime} of {duration}',
|
||||
played: 'Played',
|
||||
buffered: 'Buffered',
|
||||
currentTime: 'Current time',
|
||||
@ -3673,6 +3703,7 @@ var defaults$1 = {
|
||||
frameTitle: 'Player for {title}',
|
||||
captions: 'Captions',
|
||||
settings: 'Settings',
|
||||
menuBack: 'Go back to previous menu',
|
||||
speed: 'Speed',
|
||||
normal: 'Normal',
|
||||
quality: 'Quality',
|
||||
@ -4223,9 +4254,6 @@ var ui = {
|
||||
// If there's a media title set, use that for the label
|
||||
if (utils.is.string(this.config.title) && !utils.is.empty(this.config.title)) {
|
||||
label += ', ' + this.config.title;
|
||||
|
||||
// Set container label
|
||||
this.elements.container.setAttribute('aria-label', this.config.title);
|
||||
}
|
||||
|
||||
// If there's a play button, set label
|
||||
@ -7080,9 +7108,6 @@ var Plyr = function () {
|
||||
utils.wrap(this.media, this.elements.container);
|
||||
}
|
||||
|
||||
// Allow focus to be captured
|
||||
this.elements.container.setAttribute('tabindex', 0);
|
||||
|
||||
// Add style hook
|
||||
ui.addStyleHook.call(this);
|
||||
|
||||
|
2
dist/plyr.js.map
vendored
2
dist/plyr.js.map
vendored
File diff suppressed because one or more lines are too long
2
dist/plyr.min.js
vendored
2
dist/plyr.min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/plyr.min.js.map
vendored
2
dist/plyr.min.js.map
vendored
File diff suppressed because one or more lines are too long
62
src/js/controls.js
vendored
62
src/js/controls.js
vendored
@ -12,8 +12,6 @@ import utils from './utils';
|
||||
const browser = utils.getBrowser();
|
||||
|
||||
const controls = {
|
||||
|
||||
|
||||
// Get icon URL
|
||||
getIconUrl() {
|
||||
const url = new URL(this.config.iconUrl, window.location);
|
||||
@ -359,10 +357,14 @@ const controls = {
|
||||
createTime(type) {
|
||||
const attributes = utils.getAttributesFromSelector(this.config.selectors.display[type]);
|
||||
|
||||
const container = utils.createElement('div', utils.extend(attributes, {
|
||||
const container = utils.createElement(
|
||||
'div',
|
||||
utils.extend(attributes, {
|
||||
class: `plyr__time ${attributes.class}`,
|
||||
'aria-label': i18n.get(type, this.config),
|
||||
}), '00:00');
|
||||
}),
|
||||
'00:00',
|
||||
);
|
||||
|
||||
// Reference for updates
|
||||
this.elements.display[type] = container;
|
||||
@ -403,6 +405,19 @@ const controls = {
|
||||
list.appendChild(item);
|
||||
},
|
||||
|
||||
// Format a time for display
|
||||
formatTime(time = 0, inverted = false) {
|
||||
// Bail if the value isn't a number
|
||||
if (!utils.is.number(time)) {
|
||||
return time;
|
||||
}
|
||||
|
||||
// Always display hours if duration is over an hour
|
||||
const forceHours = utils.getHours(this.duration) > 0;
|
||||
|
||||
return utils.formatTime(time, forceHours, inverted);
|
||||
},
|
||||
|
||||
// Update the displayed time
|
||||
updateTimeDisplay(target = null, time = 0, inverted = false) {
|
||||
// Bail if there's no element to display or the value isn't a number
|
||||
@ -410,11 +425,8 @@ const controls = {
|
||||
return;
|
||||
}
|
||||
|
||||
// Always display hours if duration is over an hour
|
||||
const forceHours = utils.getHours(this.duration) > 0;
|
||||
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
target.innerText = utils.formatTime(time, forceHours, inverted);
|
||||
target.innerText = controls.formatTime(time, inverted);
|
||||
},
|
||||
|
||||
// Update volume UI and storage
|
||||
@ -509,8 +521,20 @@ const controls = {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set aria value for https://github.com/sampotts/plyr/issues/905
|
||||
// Set aria values for https://github.com/sampotts/plyr/issues/905
|
||||
if (utils.matches(range, this.config.selectors.inputs.seek)) {
|
||||
range.setAttribute('aria-valuenow', this.currentTime);
|
||||
const currentTime = controls.formatTime(this.currentTime);
|
||||
const duration = controls.formatTime(this.duration);
|
||||
const format = i18n.get('seekLabel', this.config);
|
||||
range.setAttribute('aria-valuetext', format.replace('{currentTime}', currentTime).replace('{duration}', duration));
|
||||
} else if (utils.matches(range, this.config.selectors.inputs.volume)) {
|
||||
const percent = range.value * 100;
|
||||
range.setAttribute('aria-valuenow', percent);
|
||||
range.setAttribute('aria-valuetext', `${percent}%`);
|
||||
} else {
|
||||
range.setAttribute('aria-valuenow', range.value);
|
||||
}
|
||||
|
||||
// WebKit only
|
||||
if (!browser.isWebkit) {
|
||||
@ -599,11 +623,16 @@ const controls = {
|
||||
|
||||
// Show the duration on metadataloaded or durationchange events
|
||||
durationUpdate() {
|
||||
// Bail if no ui or durationchange event triggered after playing/seek when invertTime is false
|
||||
// Bail if no UI or durationchange event triggered after playing/seek when invertTime is false
|
||||
if (!this.supported.ui || (!this.config.invertTime && this.currentTime)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update ARIA values
|
||||
if (utils.is.element(this.elements.inputs.seek)) {
|
||||
this.elements.inputs.seek.setAttribute('aria-valuemax', this.duration);
|
||||
}
|
||||
|
||||
// If there's a spot to display duration
|
||||
const hasDuration = utils.is.element(this.elements.display.duration);
|
||||
|
||||
@ -1126,9 +1155,11 @@ const controls = {
|
||||
const progress = utils.createElement('div', utils.getAttributesFromSelector(this.config.selectors.progress));
|
||||
|
||||
// Seek range slider
|
||||
progress.appendChild(controls.createRange.call(this, 'seek', {
|
||||
progress.appendChild(
|
||||
controls.createRange.call(this, 'seek', {
|
||||
id: `plyr-seek-${data.id}`,
|
||||
}));
|
||||
}),
|
||||
);
|
||||
|
||||
// Buffer progress
|
||||
progress.appendChild(controls.createProgress.call(this, 'buffer'));
|
||||
@ -1182,13 +1213,15 @@ const controls = {
|
||||
};
|
||||
|
||||
// Create the volume range slider
|
||||
volume.appendChild(controls.createRange.call(
|
||||
volume.appendChild(
|
||||
controls.createRange.call(
|
||||
this,
|
||||
'volume',
|
||||
utils.extend(attributes, {
|
||||
id: `plyr-volume-${data.id}`,
|
||||
}),
|
||||
));
|
||||
),
|
||||
);
|
||||
|
||||
this.elements.volume = volume;
|
||||
|
||||
@ -1463,7 +1496,6 @@ const controls = {
|
||||
Array.from(labels).forEach(label => {
|
||||
utils.toggleClass(label, this.config.classNames.hidden, false);
|
||||
utils.toggleClass(label, this.config.classNames.tooltip, true);
|
||||
label.setAttribute('role', 'tooltip');
|
||||
});
|
||||
}
|
||||
},
|
||||
|
@ -169,6 +169,7 @@ const defaults = {
|
||||
pause: 'Pause',
|
||||
fastForward: 'Forward {seektime}s',
|
||||
seek: 'Seek',
|
||||
seekLabel: '{currentTime} of {duration}',
|
||||
played: 'Played',
|
||||
buffered: 'Buffered',
|
||||
currentTime: 'Current time',
|
||||
@ -183,6 +184,7 @@ const defaults = {
|
||||
frameTitle: 'Player for {title}',
|
||||
captions: 'Captions',
|
||||
settings: 'Settings',
|
||||
menuBack: 'Go back to previous menu',
|
||||
speed: 'Speed',
|
||||
normal: 'Normal',
|
||||
quality: 'Quality',
|
||||
|
@ -260,9 +260,6 @@ class Plyr {
|
||||
utils.wrap(this.media, this.elements.container);
|
||||
}
|
||||
|
||||
// Allow focus to be captured
|
||||
this.elements.container.setAttribute('tabindex', 0);
|
||||
|
||||
// Add style hook
|
||||
ui.addStyleHook.call(this);
|
||||
|
||||
|
@ -127,9 +127,6 @@ const ui = {
|
||||
// If there's a media title set, use that for the label
|
||||
if (utils.is.string(this.config.title) && !utils.is.empty(this.config.title)) {
|
||||
label += `, ${this.config.title}`;
|
||||
|
||||
// Set container label
|
||||
this.elements.container.setAttribute('aria-label', this.config.title);
|
||||
}
|
||||
|
||||
// If there's a play button, set label
|
||||
|
Loading…
x
Reference in New Issue
Block a user