Merge pull request #1041 from sampotts/a11y-improvements
A11y improvements
This commit is contained in:
		| @ -21,7 +21,7 @@ | |||||||
|  |  | ||||||
| Again, more changes from @friday! | Again, more changes from @friday! | ||||||
|  |  | ||||||
| -   Restore window reference in `utils.is.cue()` | -   Restore window reference in `is.cue()` | ||||||
| -   Fix InvalidStateError and IE11 issues | -   Fix InvalidStateError and IE11 issues | ||||||
| -   Respect storage being disabled for storage getter | -   Respect storage being disabled for storage getter | ||||||
|  |  | ||||||
|  | |||||||
							
								
								
									
										24
									
								
								controls.md
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								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: | 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) | -   `Array` of options (this builds the default controls based on your choices) | ||||||
| *   `String` containing the desired HTML | -   `String` containing the desired HTML | ||||||
| *   `Function` that will be executed and should return one of the above | -   `Function` that will be executed and should return one of the above | ||||||
|  |  | ||||||
| ## Using default controls | ## 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: | 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) | -   `{id}` - the dynamically generated ID for the player (for form controls) | ||||||
| *   `{seektime}` - the seek time specified in options for fast forward and rewind | -   `{seektime}` - the seek time specified in options for fast forward and rewind | ||||||
| *   `{title}` - the title of your media, if specified | -   `{title}` - the title of your media, if specified | ||||||
|  |  | ||||||
| ### Limitations | ### Limitations | ||||||
|  |  | ||||||
| *   Currently the settings menus are not supported with custom controls HTML | -   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 | -   AirPlay and PiP buttons can be added but you will have to manage feature detection | ||||||
|  |  | ||||||
| ### Example | ### Example | ||||||
|  |  | ||||||
| @ -105,7 +105,7 @@ const controls = ` | |||||||
|         <svg role="presentation"><use xlink:href="#plyr-rewind"></use></svg> |         <svg role="presentation"><use xlink:href="#plyr-rewind"></use></svg> | ||||||
|         <span class="plyr__tooltip" role="tooltip">Rewind {seektime} secs</span> |         <span class="plyr__tooltip" role="tooltip">Rewind {seektime} secs</span> | ||||||
|     </button> |     </button> | ||||||
|     <button type="button" class="plyr__control" aria-pressed="false" aria-label="Play, {title}" data-plyr="play"> |     <button type="button" class="plyr__control" aria-label="Play, {title}" data-plyr="play"> | ||||||
|         <svg class="icon--pressed" role="presentation"><use xlink:href="#plyr-pause"></use></svg> |         <svg class="icon--pressed" role="presentation"><use xlink:href="#plyr-pause"></use></svg> | ||||||
|         <svg class="icon--not-pressed" role="presentation"><use xlink:href="#plyr-play"></use></svg> |         <svg class="icon--not-pressed" role="presentation"><use xlink:href="#plyr-play"></use></svg> | ||||||
|         <span class="label--pressed plyr__tooltip" role="tooltip">Pause</span> |         <span class="label--pressed plyr__tooltip" role="tooltip">Pause</span> | ||||||
| @ -122,7 +122,7 @@ const controls = ` | |||||||
|     </div> |     </div> | ||||||
|     <div class="plyr__time plyr__time--current" aria-label="Current time">00:00</div> |     <div class="plyr__time plyr__time--current" aria-label="Current time">00:00</div> | ||||||
|     <div class="plyr__time plyr__time--duration" aria-label="Duration">00:00</div> |     <div class="plyr__time plyr__time--duration" aria-label="Duration">00:00</div> | ||||||
|     <button type="button" class="plyr__control" aria-pressed="false" aria-label="Mute" data-plyr="mute"> |     <button type="button" class="plyr__control" aria-label="Mute" data-plyr="mute"> | ||||||
|         <svg class="icon--pressed" role="presentation"><use xlink:href="#plyr-muted"></use></svg> |         <svg class="icon--pressed" role="presentation"><use xlink:href="#plyr-muted"></use></svg> | ||||||
|         <svg class="icon--not-pressed" role="presentation"><use xlink:href="#plyr-volume"></use></svg> |         <svg class="icon--not-pressed" role="presentation"><use xlink:href="#plyr-volume"></use></svg> | ||||||
|         <span class="label--pressed plyr__tooltip" role="tooltip">Unmute</span> |         <span class="label--pressed plyr__tooltip" role="tooltip">Unmute</span> | ||||||
| @ -131,13 +131,13 @@ const controls = ` | |||||||
|     <div class="plyr__volume"> |     <div class="plyr__volume"> | ||||||
|         <input data-plyr="volume" type="range" min="0" max="1" step="0.05" value="1" autocomplete="off" aria-label="Volume"> |         <input data-plyr="volume" type="range" min="0" max="1" step="0.05" value="1" autocomplete="off" aria-label="Volume"> | ||||||
|     </div> |     </div> | ||||||
|     <button type="button" class="plyr__control" aria-pressed="true" 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--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> |         <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--pressed plyr__tooltip" role="tooltip">Disable captions</span> | ||||||
|         <span class="label--not-pressed plyr__tooltip" role="tooltip">Enable captions</span> |         <span class="label--not-pressed plyr__tooltip" role="tooltip">Enable captions</span> | ||||||
|     </button> |     </button> | ||||||
|     <button type="button" class="plyr__control" aria-pressed="false" 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--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> |         <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> |         <span class="label--pressed plyr__tooltip" role="tooltip">Exit fullscreen</span> | ||||||
|  | |||||||
							
								
								
									
										2
									
								
								demo/dist/demo.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								demo/dist/demo.css
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								dist/plyr.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								dist/plyr.css
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										154
									
								
								dist/plyr.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										154
									
								
								dist/plyr.js
									
									
									
									
										vendored
									
									
								
							| @ -595,30 +595,6 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
|         toggleListener.call(this, this.elements.container, 'keydown', trap, toggle, false); |         toggleListener.call(this, this.elements.container, 'keydown', trap, toggle, false); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // Toggle aria-pressed state on a toggle button |  | ||||||
|     // http://www.ssbbartgroup.com/blog/how-not-to-misuse-aria-states-properties-and-roles |  | ||||||
|     function toggleState(element, input) { |  | ||||||
|         // If multiple elements passed |  | ||||||
|         if (is.array(element) || is.nodeList(element)) { |  | ||||||
|             Array.from(element).forEach(function (target) { |  | ||||||
|                 return toggleState(target, input); |  | ||||||
|             }); |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // Bail if no target |  | ||||||
|         if (!is.element(element)) { |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // Get state |  | ||||||
|         var pressed = element.getAttribute('aria-pressed') === 'true'; |  | ||||||
|         var state = is.boolean(input) ? input : !pressed; |  | ||||||
|  |  | ||||||
|         // Set the attribute on target |  | ||||||
|         element.setAttribute('aria-pressed', state); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // ========================================================================== |     // ========================================================================== | ||||||
|  |  | ||||||
|     var transitionEndEvent = function () { |     var transitionEndEvent = function () { | ||||||
| @ -1271,11 +1247,12 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         // Render |         // Render | ||||||
|         return '' + (inverted ? '-' : '') + hours + format(mins) + ':' + format(secs); |         return '' + (inverted && time > 0 ? '-' : '') + hours + format(mins) + ':' + format(secs); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // ========================================================================== |     // ========================================================================== | ||||||
|  |  | ||||||
|  |     // TODO: Don't export a massive object - break down and create class | ||||||
|     var controls = { |     var controls = { | ||||||
|         // Get icon URL |         // Get icon URL | ||||||
|         getIconUrl: function getIconUrl() { |         getIconUrl: function getIconUrl() { | ||||||
| @ -1289,8 +1266,7 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
|         }, |         }, | ||||||
|  |  | ||||||
|  |  | ||||||
|         // Find the UI controls and store references in custom controls |         // Find the UI controls | ||||||
|         // TODO: Allow settings menus with custom controls |  | ||||||
|         findElements: function findElements() { |         findElements: function findElements() { | ||||||
|             try { |             try { | ||||||
|                 this.elements.controls = getElement.call(this, this.config.selectors.controls.wrapper); |                 this.elements.controls = getElement.call(this, this.config.selectors.controls.wrapper); | ||||||
| @ -1386,12 +1362,11 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
|                 pip: 'PIP', |                 pip: 'PIP', | ||||||
|                 airplay: 'AirPlay' |                 airplay: 'AirPlay' | ||||||
|             }; |             }; | ||||||
|  |  | ||||||
|             var text = universals[type] || i18n.get(type, this.config); |             var text = universals[type] || i18n.get(type, this.config); | ||||||
|  |  | ||||||
|             var attributes = Object.assign({}, attr, { |             var attributes = Object.assign({}, attr, { | ||||||
|                 class: [attr.class, this.config.classNames.hidden].filter(Boolean).join(' ') |                 class: [attr.class, this.config.classNames.hidden].filter(Boolean).join(' ') | ||||||
|             }); |             }); | ||||||
|  |  | ||||||
|             return createElement('span', attributes, text); |             return createElement('span', attributes, text); | ||||||
|         }, |         }, | ||||||
|  |  | ||||||
| @ -1493,9 +1468,6 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
|                 // Label/Tooltip |                 // Label/Tooltip | ||||||
|                 button.appendChild(controls.createLabel.call(this, labelPressed, { class: 'label--pressed' })); |                 button.appendChild(controls.createLabel.call(this, labelPressed, { class: 'label--pressed' })); | ||||||
|                 button.appendChild(controls.createLabel.call(this, label, { class: 'label--not-pressed' })); |                 button.appendChild(controls.createLabel.call(this, label, { class: 'label--not-pressed' })); | ||||||
|  |  | ||||||
|                 // Add aria attributes |  | ||||||
|                 attributes['aria-pressed'] = false; |  | ||||||
|             } else { |             } else { | ||||||
|                 button.appendChild(controls.createIcon.call(this, icon)); |                 button.appendChild(controls.createIcon.call(this, icon)); | ||||||
|                 button.appendChild(controls.createLabel.call(this, label)); |                 button.appendChild(controls.createLabel.call(this, label)); | ||||||
| @ -1517,19 +1489,26 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
|                 this.elements.buttons[type] = button; |                 this.elements.buttons[type] = button; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  |             // Toggle classname when pressed property is set | ||||||
|  |             var className = this.config.classNames.controlPressed; | ||||||
|  |             Object.defineProperty(button, 'pressed', { | ||||||
|  |                 enumerable: true, | ||||||
|  |                 get: function get$$1() { | ||||||
|  |                     return hasClass(button, className); | ||||||
|  |                 }, | ||||||
|  |                 set: function set$$1() { | ||||||
|  |                     var pressed = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; | ||||||
|  |  | ||||||
|  |                     toggleClass(button, className, pressed); | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|  |  | ||||||
|             return button; |             return button; | ||||||
|         }, |         }, | ||||||
|  |  | ||||||
|  |  | ||||||
|         // Create an <input type='range'> |         // Create an <input type='range'> | ||||||
|         createRange: function createRange(type, attributes) { |         createRange: function createRange(type, attributes) { | ||||||
|             // Seek label |  | ||||||
|             var label = createElement('label', { |  | ||||||
|                 for: attributes.id, |  | ||||||
|                 id: attributes.id + '-label', |  | ||||||
|                 class: this.config.classNames.hidden |  | ||||||
|             }, i18n.get(type, this.config)); |  | ||||||
|  |  | ||||||
|             // Seek input |             // Seek input | ||||||
|             var input = createElement('input', extend(getAttributesFromSelector(this.config.selectors.inputs[type]), { |             var input = createElement('input', extend(getAttributesFromSelector(this.config.selectors.inputs[type]), { | ||||||
|                 type: 'range', |                 type: 'range', | ||||||
| @ -1540,7 +1519,7 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
|                 autocomplete: 'off', |                 autocomplete: 'off', | ||||||
|                 // A11y fixes for https://github.com/sampotts/plyr/issues/905 |                 // A11y fixes for https://github.com/sampotts/plyr/issues/905 | ||||||
|                 role: 'slider', |                 role: 'slider', | ||||||
|                 'aria-labelledby': attributes.id + '-label', |                 'aria-label': i18n.get(type, this.config), | ||||||
|                 'aria-valuemin': 0, |                 'aria-valuemin': 0, | ||||||
|                 'aria-valuemax': 100, |                 'aria-valuemax': 100, | ||||||
|                 'aria-valuenow': 0 |                 'aria-valuenow': 0 | ||||||
| @ -1551,10 +1530,7 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
|             // Set the fill for webkit now |             // Set the fill for webkit now | ||||||
|             controls.updateRangeFill.call(this, input); |             controls.updateRangeFill.call(this, input); | ||||||
|  |  | ||||||
|             return { |             return input; | ||||||
|                 label: label, |  | ||||||
|                 input: input |  | ||||||
|             }; |  | ||||||
|         }, |         }, | ||||||
|  |  | ||||||
|  |  | ||||||
| @ -1576,7 +1552,6 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
|                     played: 'played', |                     played: 'played', | ||||||
|                     buffer: 'buffered' |                     buffer: 'buffered' | ||||||
|                 }[type]; |                 }[type]; | ||||||
|  |  | ||||||
|                 var suffix = suffixKey ? i18n.get(suffixKey, this.config) : ''; |                 var suffix = suffixKey ? i18n.get(suffixKey, this.config) : ''; | ||||||
|  |  | ||||||
|                 progress.innerText = '% ' + suffix.toLowerCase(); |                 progress.innerText = '% ' + suffix.toLowerCase(); | ||||||
| @ -1644,6 +1619,23 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
|         }, |         }, | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         // Format a time for display | ||||||
|  |         formatTime: function formatTime$$1() { | ||||||
|  |             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 (!is.number(time)) { | ||||||
|  |                 return time; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // Always display hours if duration is over an hour | ||||||
|  |             var forceHours = getHours(this.duration) > 0; | ||||||
|  |  | ||||||
|  |             return formatTime(time, forceHours, inverted); | ||||||
|  |         }, | ||||||
|  |  | ||||||
|  |  | ||||||
|         // Update the displayed time |         // Update the displayed time | ||||||
|         updateTimeDisplay: function updateTimeDisplay() { |         updateTimeDisplay: function updateTimeDisplay() { | ||||||
|             var target = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; |             var target = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; | ||||||
| @ -1655,11 +1647,8 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             // Always display hours if duration is over an hour |  | ||||||
|             var forceHours = getHours(this.duration) > 0; |  | ||||||
|  |  | ||||||
|             // eslint-disable-next-line no-param-reassign |             // eslint-disable-next-line no-param-reassign | ||||||
|             target.innerText = formatTime(time, forceHours, inverted); |             target.innerText = controls.formatTime(time, inverted); | ||||||
|         }, |         }, | ||||||
|  |  | ||||||
|  |  | ||||||
| @ -1676,7 +1665,7 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
|  |  | ||||||
|             // Update mute state |             // Update mute state | ||||||
|             if (is.element(this.elements.buttons.mute)) { |             if (is.element(this.elements.buttons.mute)) { | ||||||
|                 toggleState(this.elements.buttons.mute, this.muted || this.volume === 0); |                 this.elements.buttons.mute.pressed = this.muted || this.volume === 0; | ||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|  |  | ||||||
| @ -1762,8 +1751,20 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             // Set aria value for https://github.com/sampotts/plyr/issues/905 |             // Set aria values for https://github.com/sampotts/plyr/issues/905 | ||||||
|  |             if (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$$1 = i18n.get('seekLabel', this.config); | ||||||
|  |                 range.setAttribute('aria-valuetext', format$$1.replace('{currentTime}', currentTime).replace('{duration}', duration)); | ||||||
|  |             } else if (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); |                 range.setAttribute('aria-valuenow', range.value); | ||||||
|  |             } | ||||||
|  |  | ||||||
|             // WebKit only |             // WebKit only | ||||||
|             if (!browser.isWebkit) { |             if (!browser.isWebkit) { | ||||||
| @ -1849,11 +1850,16 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
|  |  | ||||||
|         // Show the duration on metadataloaded or durationchange events |         // Show the duration on metadataloaded or durationchange events | ||||||
|         durationUpdate: function durationUpdate() { |         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) { |             if (!this.supported.ui || !this.config.invertTime && this.currentTime) { | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  |             // Update ARIA values | ||||||
|  |             if (is.element(this.elements.inputs.seek)) { | ||||||
|  |                 this.elements.inputs.seek.setAttribute('aria-valuemax', this.duration); | ||||||
|  |             } | ||||||
|  |  | ||||||
|             // If there's a spot to display duration |             // If there's a spot to display duration | ||||||
|             var hasDuration = is.element(this.elements.display.duration); |             var hasDuration = is.element(this.elements.display.duration); | ||||||
|  |  | ||||||
| @ -2379,11 +2385,9 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
|                 var progress = createElement('div', getAttributesFromSelector(this.config.selectors.progress)); |                 var progress = createElement('div', getAttributesFromSelector(this.config.selectors.progress)); | ||||||
|  |  | ||||||
|                 // Seek range slider |                 // Seek range slider | ||||||
|                 var seek = controls.createRange.call(this, 'seek', { |                 progress.appendChild(controls.createRange.call(this, 'seek', { | ||||||
|                     id: 'plyr-seek-' + data.id |                     id: 'plyr-seek-' + data.id | ||||||
|                 }); |                 })); | ||||||
|                 progress.appendChild(seek.label); |  | ||||||
|                 progress.appendChild(seek.input); |  | ||||||
|  |  | ||||||
|                 // Buffer progress |                 // Buffer progress | ||||||
|                 progress.appendChild(controls.createProgress.call(this, 'buffer')); |                 progress.appendChild(controls.createProgress.call(this, 'buffer')); | ||||||
| @ -2433,11 +2437,9 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
|                 }; |                 }; | ||||||
|  |  | ||||||
|                 // Create the volume range slider |                 // Create the volume range slider | ||||||
|                 var range = controls.createRange.call(this, 'volume', extend(attributes, { |                 volume.appendChild(controls.createRange.call(this, 'volume', extend(attributes, { | ||||||
|                     id: 'plyr-volume-' + data.id |                     id: 'plyr-volume-' + data.id | ||||||
|                 })); |                 }))); | ||||||
|                 volume.appendChild(range.label); |  | ||||||
|                 volume.appendChild(range.input); |  | ||||||
|  |  | ||||||
|                 this.elements.volume = volume; |                 this.elements.volume = volume; | ||||||
|  |  | ||||||
| @ -2702,7 +2704,6 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
|                 Array.from(labels).forEach(function (label) { |                 Array.from(labels).forEach(function (label) { | ||||||
|                     toggleClass(label, _this8.config.classNames.hidden, false); |                     toggleClass(label, _this8.config.classNames.hidden, false); | ||||||
|                     toggleClass(label, _this8.config.classNames.tooltip, true); |                     toggleClass(label, _this8.config.classNames.tooltip, true); | ||||||
|                     label.setAttribute('role', 'tooltip'); |  | ||||||
|                 }); |                 }); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @ -2977,7 +2978,7 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 // Toggle state |                 // Toggle state | ||||||
|                 toggleState(this.elements.buttons.captions, active); |                 this.elements.buttons.captions.pressed = active; | ||||||
|  |  | ||||||
|                 // Add class hook |                 // Add class hook | ||||||
|                 toggleClass(this.elements.container, activeClass, active); |                 toggleClass(this.elements.container, activeClass, active); | ||||||
| @ -3219,6 +3220,10 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
|         // Only allow one media playing at once (vimeo only) |         // Only allow one media playing at once (vimeo only) | ||||||
|         autopause: true, |         autopause: true, | ||||||
|  |  | ||||||
|  |         // Allow inline playback on iOS (this effects YouTube/Vimeo - HTML5 requires the attribute present) | ||||||
|  |         // TODO: Remove iosNative fullscreen option in favour of this (logic needs work) | ||||||
|  |         playsinline: true, | ||||||
|  |  | ||||||
|         // Default time to skip when rewind/fast forward |         // Default time to skip when rewind/fast forward | ||||||
|         seekTime: 10, |         seekTime: 10, | ||||||
|  |  | ||||||
| @ -3332,6 +3337,7 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
|             pause: 'Pause', |             pause: 'Pause', | ||||||
|             fastForward: 'Forward {seektime}s', |             fastForward: 'Forward {seektime}s', | ||||||
|             seek: 'Seek', |             seek: 'Seek', | ||||||
|  |             seekLabel: '{currentTime} of {duration}', | ||||||
|             played: 'Played', |             played: 'Played', | ||||||
|             buffered: 'Buffered', |             buffered: 'Buffered', | ||||||
|             currentTime: 'Current time', |             currentTime: 'Current time', | ||||||
| @ -3346,6 +3352,7 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
|             frameTitle: 'Player for {title}', |             frameTitle: 'Player for {title}', | ||||||
|             captions: 'Captions', |             captions: 'Captions', | ||||||
|             settings: 'Settings', |             settings: 'Settings', | ||||||
|  |             menuBack: 'Go back to previous menu', | ||||||
|             speed: 'Speed', |             speed: 'Speed', | ||||||
|             normal: 'Normal', |             normal: 'Normal', | ||||||
|             quality: 'Quality', |             quality: 'Quality', | ||||||
| @ -3475,6 +3482,7 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
|             posterEnabled: 'plyr__poster-enabled', |             posterEnabled: 'plyr__poster-enabled', | ||||||
|             ads: 'plyr__ads', |             ads: 'plyr__ads', | ||||||
|             control: 'plyr__control', |             control: 'plyr__control', | ||||||
|  |             controlPressed: 'plyr__control--pressed', | ||||||
|             playing: 'plyr--playing', |             playing: 'plyr--playing', | ||||||
|             paused: 'plyr--paused', |             paused: 'plyr--paused', | ||||||
|             stopped: 'plyr--stopped', |             stopped: 'plyr--stopped', | ||||||
| @ -3616,7 +3624,7 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
|         // Update toggle button |         // Update toggle button | ||||||
|         var button = this.player.elements.buttons.fullscreen; |         var button = this.player.elements.buttons.fullscreen; | ||||||
|         if (is.element(button)) { |         if (is.element(button)) { | ||||||
|             toggleState(button, this.active); |             button.pressed = this.active; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // Trigger an event |         // Trigger an event | ||||||
| @ -3986,9 +3994,6 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
|             // If there's a media title set, use that for the label |             // If there's a media title set, use that for the label | ||||||
|             if (is.string(this.config.title) && !is.empty(this.config.title)) { |             if (is.string(this.config.title) && !is.empty(this.config.title)) { | ||||||
|                 label += ', ' + 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 |             // If there's a play button, set label | ||||||
| @ -4068,13 +4073,17 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
|  |  | ||||||
|         // Check playing state |         // Check playing state | ||||||
|         checkPlaying: function checkPlaying(event) { |         checkPlaying: function checkPlaying(event) { | ||||||
|  |             var _this3 = this; | ||||||
|  |  | ||||||
|             // Class hooks |             // Class hooks | ||||||
|             toggleClass(this.elements.container, this.config.classNames.playing, this.playing); |             toggleClass(this.elements.container, this.config.classNames.playing, this.playing); | ||||||
|             toggleClass(this.elements.container, this.config.classNames.paused, this.paused); |             toggleClass(this.elements.container, this.config.classNames.paused, this.paused); | ||||||
|             toggleClass(this.elements.container, this.config.classNames.stopped, this.stopped); |             toggleClass(this.elements.container, this.config.classNames.stopped, this.stopped); | ||||||
|  |  | ||||||
|             // Set ARIA state |             // Set state | ||||||
|             toggleState(this.elements.buttons.play, this.playing); |             Array.from(this.elements.buttons.play).forEach(function (target) { | ||||||
|  |                 target.pressed = _this3.playing; | ||||||
|  |             }); | ||||||
|  |  | ||||||
|             // Only update controls on non timeupdate events |             // Only update controls on non timeupdate events | ||||||
|             if (is.event(event) && event.type === 'timeupdate') { |             if (is.event(event) && event.type === 'timeupdate') { | ||||||
| @ -4088,7 +4097,7 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
|  |  | ||||||
|         // Check if media is loading |         // Check if media is loading | ||||||
|         checkLoading: function checkLoading(event) { |         checkLoading: function checkLoading(event) { | ||||||
|             var _this3 = this; |             var _this4 = this; | ||||||
|  |  | ||||||
|             this.loading = ['stalled', 'waiting'].includes(event.type); |             this.loading = ['stalled', 'waiting'].includes(event.type); | ||||||
|  |  | ||||||
| @ -4098,10 +4107,10 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
|             // Timer to prevent flicker when seeking |             // Timer to prevent flicker when seeking | ||||||
|             this.timers.loading = setTimeout(function () { |             this.timers.loading = setTimeout(function () { | ||||||
|                 // Update progress bar loading class state |                 // Update progress bar loading class state | ||||||
|                 toggleClass(_this3.elements.container, _this3.config.classNames.loading, _this3.loading); |                 toggleClass(_this4.elements.container, _this4.config.classNames.loading, _this4.loading); | ||||||
|  |  | ||||||
|                 // Update controls visibility |                 // Update controls visibility | ||||||
|                 ui.toggleControls.call(_this3); |                 ui.toggleControls.call(_this4); | ||||||
|             }, this.loading ? 250 : 0); |             }, this.loading ? 250 : 0); | ||||||
|         }, |         }, | ||||||
|  |  | ||||||
| @ -7131,9 +7140,6 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
|                 wrap(this.media, this.elements.container); |                 wrap(this.media, this.elements.container); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             // Allow focus to be captured |  | ||||||
|             this.elements.container.setAttribute('tabindex', 0); |  | ||||||
|  |  | ||||||
|             // Add style hook |             // Add style hook | ||||||
|             ui.addStyleHook.call(this); |             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
											
										
									
								
							
							
								
								
									
										154
									
								
								dist/plyr.polyfilled.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										154
									
								
								dist/plyr.polyfilled.js
									
									
									
									
										vendored
									
									
								
							| @ -5981,30 +5981,6 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
| 	    toggleListener.call(this, this.elements.container, 'keydown', trap, toggle, false); | 	    toggleListener.call(this, this.elements.container, 'keydown', trap, toggle, false); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Toggle aria-pressed state on a toggle button |  | ||||||
| 	// http://www.ssbbartgroup.com/blog/how-not-to-misuse-aria-states-properties-and-roles |  | ||||||
| 	function toggleState(element, input) { |  | ||||||
| 	    // If multiple elements passed |  | ||||||
| 	    if (is$1.array(element) || is$1.nodeList(element)) { |  | ||||||
| 	        Array.from(element).forEach(function (target) { |  | ||||||
| 	            return toggleState(target, input); |  | ||||||
| 	        }); |  | ||||||
| 	        return; |  | ||||||
| 	    } |  | ||||||
|  |  | ||||||
| 	    // Bail if no target |  | ||||||
| 	    if (!is$1.element(element)) { |  | ||||||
| 	        return; |  | ||||||
| 	    } |  | ||||||
|  |  | ||||||
| 	    // Get state |  | ||||||
| 	    var pressed = element.getAttribute('aria-pressed') === 'true'; |  | ||||||
| 	    var state = is$1.boolean(input) ? input : !pressed; |  | ||||||
|  |  | ||||||
| 	    // Set the attribute on target |  | ||||||
| 	    element.setAttribute('aria-pressed', state); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// ========================================================================== | 	// ========================================================================== | ||||||
|  |  | ||||||
| 	var transitionEndEvent = function () { | 	var transitionEndEvent = function () { | ||||||
| @ -6657,11 +6633,12 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
| 	    } | 	    } | ||||||
|  |  | ||||||
| 	    // Render | 	    // Render | ||||||
| 	    return '' + (inverted ? '-' : '') + hours + format(mins) + ':' + format(secs); | 	    return '' + (inverted && time > 0 ? '-' : '') + hours + format(mins) + ':' + format(secs); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// ========================================================================== | 	// ========================================================================== | ||||||
|  |  | ||||||
|  | 	// TODO: Don't export a massive object - break down and create class | ||||||
| 	var controls = { | 	var controls = { | ||||||
| 	    // Get icon URL | 	    // Get icon URL | ||||||
| 	    getIconUrl: function getIconUrl() { | 	    getIconUrl: function getIconUrl() { | ||||||
| @ -6675,8 +6652,7 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
| 	    }, | 	    }, | ||||||
|  |  | ||||||
|  |  | ||||||
| 	    // Find the UI controls and store references in custom controls | 	    // Find the UI controls | ||||||
| 	    // TODO: Allow settings menus with custom controls |  | ||||||
| 	    findElements: function findElements() { | 	    findElements: function findElements() { | ||||||
| 	        try { | 	        try { | ||||||
| 	            this.elements.controls = getElement.call(this, this.config.selectors.controls.wrapper); | 	            this.elements.controls = getElement.call(this, this.config.selectors.controls.wrapper); | ||||||
| @ -6772,12 +6748,11 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
| 	            pip: 'PIP', | 	            pip: 'PIP', | ||||||
| 	            airplay: 'AirPlay' | 	            airplay: 'AirPlay' | ||||||
| 	        }; | 	        }; | ||||||
|  |  | ||||||
| 	        var text = universals[type] || i18n.get(type, this.config); | 	        var text = universals[type] || i18n.get(type, this.config); | ||||||
|  |  | ||||||
| 	        var attributes = Object.assign({}, attr, { | 	        var attributes = Object.assign({}, attr, { | ||||||
| 	            class: [attr.class, this.config.classNames.hidden].filter(Boolean).join(' ') | 	            class: [attr.class, this.config.classNames.hidden].filter(Boolean).join(' ') | ||||||
| 	        }); | 	        }); | ||||||
|  |  | ||||||
| 	        return createElement('span', attributes, text); | 	        return createElement('span', attributes, text); | ||||||
| 	    }, | 	    }, | ||||||
|  |  | ||||||
| @ -6879,9 +6854,6 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
| 	            // Label/Tooltip | 	            // Label/Tooltip | ||||||
| 	            button.appendChild(controls.createLabel.call(this, labelPressed, { class: 'label--pressed' })); | 	            button.appendChild(controls.createLabel.call(this, labelPressed, { class: 'label--pressed' })); | ||||||
| 	            button.appendChild(controls.createLabel.call(this, label, { class: 'label--not-pressed' })); | 	            button.appendChild(controls.createLabel.call(this, label, { class: 'label--not-pressed' })); | ||||||
|  |  | ||||||
| 	            // Add aria attributes |  | ||||||
| 	            attributes['aria-pressed'] = false; |  | ||||||
| 	        } else { | 	        } else { | ||||||
| 	            button.appendChild(controls.createIcon.call(this, icon)); | 	            button.appendChild(controls.createIcon.call(this, icon)); | ||||||
| 	            button.appendChild(controls.createLabel.call(this, label)); | 	            button.appendChild(controls.createLabel.call(this, label)); | ||||||
| @ -6903,19 +6875,26 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
| 	            this.elements.buttons[type] = button; | 	            this.elements.buttons[type] = button; | ||||||
| 	        } | 	        } | ||||||
|  |  | ||||||
|  | 	        // Toggle classname when pressed property is set | ||||||
|  | 	        var className = this.config.classNames.controlPressed; | ||||||
|  | 	        Object.defineProperty(button, 'pressed', { | ||||||
|  | 	            enumerable: true, | ||||||
|  | 	            get: function get() { | ||||||
|  | 	                return hasClass(button, className); | ||||||
|  | 	            }, | ||||||
|  | 	            set: function set() { | ||||||
|  | 	                var pressed = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; | ||||||
|  |  | ||||||
|  | 	                toggleClass(button, className, pressed); | ||||||
|  | 	            } | ||||||
|  | 	        }); | ||||||
|  |  | ||||||
| 	        return button; | 	        return button; | ||||||
| 	    }, | 	    }, | ||||||
|  |  | ||||||
|  |  | ||||||
| 	    // Create an <input type='range'> | 	    // Create an <input type='range'> | ||||||
| 	    createRange: function createRange(type, attributes) { | 	    createRange: function createRange(type, attributes) { | ||||||
| 	        // Seek label |  | ||||||
| 	        var label = createElement('label', { |  | ||||||
| 	            for: attributes.id, |  | ||||||
| 	            id: attributes.id + '-label', |  | ||||||
| 	            class: this.config.classNames.hidden |  | ||||||
| 	        }, i18n.get(type, this.config)); |  | ||||||
|  |  | ||||||
| 	        // Seek input | 	        // Seek input | ||||||
| 	        var input = createElement('input', extend(getAttributesFromSelector(this.config.selectors.inputs[type]), { | 	        var input = createElement('input', extend(getAttributesFromSelector(this.config.selectors.inputs[type]), { | ||||||
| 	            type: 'range', | 	            type: 'range', | ||||||
| @ -6926,7 +6905,7 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
| 	            autocomplete: 'off', | 	            autocomplete: 'off', | ||||||
| 	            // A11y fixes for https://github.com/sampotts/plyr/issues/905 | 	            // A11y fixes for https://github.com/sampotts/plyr/issues/905 | ||||||
| 	            role: 'slider', | 	            role: 'slider', | ||||||
| 	            'aria-labelledby': attributes.id + '-label', | 	            'aria-label': i18n.get(type, this.config), | ||||||
| 	            'aria-valuemin': 0, | 	            'aria-valuemin': 0, | ||||||
| 	            'aria-valuemax': 100, | 	            'aria-valuemax': 100, | ||||||
| 	            'aria-valuenow': 0 | 	            'aria-valuenow': 0 | ||||||
| @ -6937,10 +6916,7 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
| 	        // Set the fill for webkit now | 	        // Set the fill for webkit now | ||||||
| 	        controls.updateRangeFill.call(this, input); | 	        controls.updateRangeFill.call(this, input); | ||||||
|  |  | ||||||
| 	        return { | 	        return input; | ||||||
| 	            label: label, |  | ||||||
| 	            input: input |  | ||||||
| 	        }; |  | ||||||
| 	    }, | 	    }, | ||||||
|  |  | ||||||
|  |  | ||||||
| @ -6962,7 +6938,6 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
| 	                played: 'played', | 	                played: 'played', | ||||||
| 	                buffer: 'buffered' | 	                buffer: 'buffered' | ||||||
| 	            }[type]; | 	            }[type]; | ||||||
|  |  | ||||||
| 	            var suffix = suffixKey ? i18n.get(suffixKey, this.config) : ''; | 	            var suffix = suffixKey ? i18n.get(suffixKey, this.config) : ''; | ||||||
|  |  | ||||||
| 	            progress.innerText = '% ' + suffix.toLowerCase(); | 	            progress.innerText = '% ' + suffix.toLowerCase(); | ||||||
| @ -7030,6 +7005,23 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
| 	    }, | 	    }, | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	    // Format a time for display | ||||||
|  | 	    formatTime: function formatTime$$1() { | ||||||
|  | 	        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 (!is$1.number(time)) { | ||||||
|  | 	            return time; | ||||||
|  | 	        } | ||||||
|  |  | ||||||
|  | 	        // Always display hours if duration is over an hour | ||||||
|  | 	        var forceHours = getHours(this.duration) > 0; | ||||||
|  |  | ||||||
|  | 	        return formatTime(time, forceHours, inverted); | ||||||
|  | 	    }, | ||||||
|  |  | ||||||
|  |  | ||||||
| 	    // Update the displayed time | 	    // Update the displayed time | ||||||
| 	    updateTimeDisplay: function updateTimeDisplay() { | 	    updateTimeDisplay: function updateTimeDisplay() { | ||||||
| 	        var target = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; | 	        var target = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; | ||||||
| @ -7041,11 +7033,8 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
| 	            return; | 	            return; | ||||||
| 	        } | 	        } | ||||||
|  |  | ||||||
| 	        // Always display hours if duration is over an hour |  | ||||||
| 	        var forceHours = getHours(this.duration) > 0; |  | ||||||
|  |  | ||||||
| 	        // eslint-disable-next-line no-param-reassign | 	        // eslint-disable-next-line no-param-reassign | ||||||
| 	        target.innerText = formatTime(time, forceHours, inverted); | 	        target.innerText = controls.formatTime(time, inverted); | ||||||
| 	    }, | 	    }, | ||||||
|  |  | ||||||
|  |  | ||||||
| @ -7062,7 +7051,7 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
|  |  | ||||||
| 	        // Update mute state | 	        // Update mute state | ||||||
| 	        if (is$1.element(this.elements.buttons.mute)) { | 	        if (is$1.element(this.elements.buttons.mute)) { | ||||||
| 	            toggleState(this.elements.buttons.mute, this.muted || this.volume === 0); | 	            this.elements.buttons.mute.pressed = this.muted || this.volume === 0; | ||||||
| 	        } | 	        } | ||||||
| 	    }, | 	    }, | ||||||
|  |  | ||||||
| @ -7148,8 +7137,20 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
| 	            return; | 	            return; | ||||||
| 	        } | 	        } | ||||||
|  |  | ||||||
| 	        // Set aria value for https://github.com/sampotts/plyr/issues/905 | 	        // Set aria values for https://github.com/sampotts/plyr/issues/905 | ||||||
|  | 	        if (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$$1 = i18n.get('seekLabel', this.config); | ||||||
|  | 	            range.setAttribute('aria-valuetext', format$$1.replace('{currentTime}', currentTime).replace('{duration}', duration)); | ||||||
|  | 	        } else if (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); | 	            range.setAttribute('aria-valuenow', range.value); | ||||||
|  | 	        } | ||||||
|  |  | ||||||
| 	        // WebKit only | 	        // WebKit only | ||||||
| 	        if (!browser.isWebkit) { | 	        if (!browser.isWebkit) { | ||||||
| @ -7235,11 +7236,16 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
|  |  | ||||||
| 	    // Show the duration on metadataloaded or durationchange events | 	    // Show the duration on metadataloaded or durationchange events | ||||||
| 	    durationUpdate: function durationUpdate() { | 	    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) { | 	        if (!this.supported.ui || !this.config.invertTime && this.currentTime) { | ||||||
| 	            return; | 	            return; | ||||||
| 	        } | 	        } | ||||||
|  |  | ||||||
|  | 	        // Update ARIA values | ||||||
|  | 	        if (is$1.element(this.elements.inputs.seek)) { | ||||||
|  | 	            this.elements.inputs.seek.setAttribute('aria-valuemax', this.duration); | ||||||
|  | 	        } | ||||||
|  |  | ||||||
| 	        // If there's a spot to display duration | 	        // If there's a spot to display duration | ||||||
| 	        var hasDuration = is$1.element(this.elements.display.duration); | 	        var hasDuration = is$1.element(this.elements.display.duration); | ||||||
|  |  | ||||||
| @ -7765,11 +7771,9 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
| 	            var progress = createElement('div', getAttributesFromSelector(this.config.selectors.progress)); | 	            var progress = createElement('div', getAttributesFromSelector(this.config.selectors.progress)); | ||||||
|  |  | ||||||
| 	            // Seek range slider | 	            // Seek range slider | ||||||
| 	            var seek = controls.createRange.call(this, 'seek', { | 	            progress.appendChild(controls.createRange.call(this, 'seek', { | ||||||
| 	                id: 'plyr-seek-' + data.id | 	                id: 'plyr-seek-' + data.id | ||||||
| 	            }); | 	            })); | ||||||
| 	            progress.appendChild(seek.label); |  | ||||||
| 	            progress.appendChild(seek.input); |  | ||||||
|  |  | ||||||
| 	            // Buffer progress | 	            // Buffer progress | ||||||
| 	            progress.appendChild(controls.createProgress.call(this, 'buffer')); | 	            progress.appendChild(controls.createProgress.call(this, 'buffer')); | ||||||
| @ -7819,11 +7823,9 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
| 	            }; | 	            }; | ||||||
|  |  | ||||||
| 	            // Create the volume range slider | 	            // Create the volume range slider | ||||||
| 	            var range = controls.createRange.call(this, 'volume', extend(attributes, { | 	            volume.appendChild(controls.createRange.call(this, 'volume', extend(attributes, { | ||||||
| 	                id: 'plyr-volume-' + data.id | 	                id: 'plyr-volume-' + data.id | ||||||
| 	            })); | 	            }))); | ||||||
| 	            volume.appendChild(range.label); |  | ||||||
| 	            volume.appendChild(range.input); |  | ||||||
|  |  | ||||||
| 	            this.elements.volume = volume; | 	            this.elements.volume = volume; | ||||||
|  |  | ||||||
| @ -8088,7 +8090,6 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
| 	            Array.from(labels).forEach(function (label) { | 	            Array.from(labels).forEach(function (label) { | ||||||
| 	                toggleClass(label, _this8.config.classNames.hidden, false); | 	                toggleClass(label, _this8.config.classNames.hidden, false); | ||||||
| 	                toggleClass(label, _this8.config.classNames.tooltip, true); | 	                toggleClass(label, _this8.config.classNames.tooltip, true); | ||||||
| 	                label.setAttribute('role', 'tooltip'); |  | ||||||
| 	            }); | 	            }); | ||||||
| 	        } | 	        } | ||||||
| 	    } | 	    } | ||||||
| @ -8363,7 +8364,7 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
| 	            } | 	            } | ||||||
|  |  | ||||||
| 	            // Toggle state | 	            // Toggle state | ||||||
| 	            toggleState(this.elements.buttons.captions, active); | 	            this.elements.buttons.captions.pressed = active; | ||||||
|  |  | ||||||
| 	            // Add class hook | 	            // Add class hook | ||||||
| 	            toggleClass(this.elements.container, activeClass, active); | 	            toggleClass(this.elements.container, activeClass, active); | ||||||
| @ -8605,6 +8606,10 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
| 	    // Only allow one media playing at once (vimeo only) | 	    // Only allow one media playing at once (vimeo only) | ||||||
| 	    autopause: true, | 	    autopause: true, | ||||||
|  |  | ||||||
|  | 	    // Allow inline playback on iOS (this effects YouTube/Vimeo - HTML5 requires the attribute present) | ||||||
|  | 	    // TODO: Remove iosNative fullscreen option in favour of this (logic needs work) | ||||||
|  | 	    playsinline: true, | ||||||
|  |  | ||||||
| 	    // Default time to skip when rewind/fast forward | 	    // Default time to skip when rewind/fast forward | ||||||
| 	    seekTime: 10, | 	    seekTime: 10, | ||||||
|  |  | ||||||
| @ -8718,6 +8723,7 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
| 	        pause: 'Pause', | 	        pause: 'Pause', | ||||||
| 	        fastForward: 'Forward {seektime}s', | 	        fastForward: 'Forward {seektime}s', | ||||||
| 	        seek: 'Seek', | 	        seek: 'Seek', | ||||||
|  | 	        seekLabel: '{currentTime} of {duration}', | ||||||
| 	        played: 'Played', | 	        played: 'Played', | ||||||
| 	        buffered: 'Buffered', | 	        buffered: 'Buffered', | ||||||
| 	        currentTime: 'Current time', | 	        currentTime: 'Current time', | ||||||
| @ -8732,6 +8738,7 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
| 	        frameTitle: 'Player for {title}', | 	        frameTitle: 'Player for {title}', | ||||||
| 	        captions: 'Captions', | 	        captions: 'Captions', | ||||||
| 	        settings: 'Settings', | 	        settings: 'Settings', | ||||||
|  | 	        menuBack: 'Go back to previous menu', | ||||||
| 	        speed: 'Speed', | 	        speed: 'Speed', | ||||||
| 	        normal: 'Normal', | 	        normal: 'Normal', | ||||||
| 	        quality: 'Quality', | 	        quality: 'Quality', | ||||||
| @ -8861,6 +8868,7 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
| 	        posterEnabled: 'plyr__poster-enabled', | 	        posterEnabled: 'plyr__poster-enabled', | ||||||
| 	        ads: 'plyr__ads', | 	        ads: 'plyr__ads', | ||||||
| 	        control: 'plyr__control', | 	        control: 'plyr__control', | ||||||
|  | 	        controlPressed: 'plyr__control--pressed', | ||||||
| 	        playing: 'plyr--playing', | 	        playing: 'plyr--playing', | ||||||
| 	        paused: 'plyr--paused', | 	        paused: 'plyr--paused', | ||||||
| 	        stopped: 'plyr--stopped', | 	        stopped: 'plyr--stopped', | ||||||
| @ -9002,7 +9010,7 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
| 	    // Update toggle button | 	    // Update toggle button | ||||||
| 	    var button = this.player.elements.buttons.fullscreen; | 	    var button = this.player.elements.buttons.fullscreen; | ||||||
| 	    if (is$1.element(button)) { | 	    if (is$1.element(button)) { | ||||||
| 	        toggleState(button, this.active); | 	        button.pressed = this.active; | ||||||
| 	    } | 	    } | ||||||
|  |  | ||||||
| 	    // Trigger an event | 	    // Trigger an event | ||||||
| @ -9372,9 +9380,6 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
| 	        // If there's a media title set, use that for the label | 	        // If there's a media title set, use that for the label | ||||||
| 	        if (is$1.string(this.config.title) && !is$1.empty(this.config.title)) { | 	        if (is$1.string(this.config.title) && !is$1.empty(this.config.title)) { | ||||||
| 	            label += ', ' + 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 | 	        // If there's a play button, set label | ||||||
| @ -9454,13 +9459,17 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
|  |  | ||||||
| 	    // Check playing state | 	    // Check playing state | ||||||
| 	    checkPlaying: function checkPlaying(event) { | 	    checkPlaying: function checkPlaying(event) { | ||||||
|  | 	        var _this3 = this; | ||||||
|  |  | ||||||
| 	        // Class hooks | 	        // Class hooks | ||||||
| 	        toggleClass(this.elements.container, this.config.classNames.playing, this.playing); | 	        toggleClass(this.elements.container, this.config.classNames.playing, this.playing); | ||||||
| 	        toggleClass(this.elements.container, this.config.classNames.paused, this.paused); | 	        toggleClass(this.elements.container, this.config.classNames.paused, this.paused); | ||||||
| 	        toggleClass(this.elements.container, this.config.classNames.stopped, this.stopped); | 	        toggleClass(this.elements.container, this.config.classNames.stopped, this.stopped); | ||||||
|  |  | ||||||
| 	        // Set ARIA state | 	        // Set state | ||||||
| 	        toggleState(this.elements.buttons.play, this.playing); | 	        Array.from(this.elements.buttons.play).forEach(function (target) { | ||||||
|  | 	            target.pressed = _this3.playing; | ||||||
|  | 	        }); | ||||||
|  |  | ||||||
| 	        // Only update controls on non timeupdate events | 	        // Only update controls on non timeupdate events | ||||||
| 	        if (is$1.event(event) && event.type === 'timeupdate') { | 	        if (is$1.event(event) && event.type === 'timeupdate') { | ||||||
| @ -9474,7 +9483,7 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
|  |  | ||||||
| 	    // Check if media is loading | 	    // Check if media is loading | ||||||
| 	    checkLoading: function checkLoading(event) { | 	    checkLoading: function checkLoading(event) { | ||||||
| 	        var _this3 = this; | 	        var _this4 = this; | ||||||
|  |  | ||||||
| 	        this.loading = ['stalled', 'waiting'].includes(event.type); | 	        this.loading = ['stalled', 'waiting'].includes(event.type); | ||||||
|  |  | ||||||
| @ -9484,10 +9493,10 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
| 	        // Timer to prevent flicker when seeking | 	        // Timer to prevent flicker when seeking | ||||||
| 	        this.timers.loading = setTimeout(function () { | 	        this.timers.loading = setTimeout(function () { | ||||||
| 	            // Update progress bar loading class state | 	            // Update progress bar loading class state | ||||||
| 	            toggleClass(_this3.elements.container, _this3.config.classNames.loading, _this3.loading); | 	            toggleClass(_this4.elements.container, _this4.config.classNames.loading, _this4.loading); | ||||||
|  |  | ||||||
| 	            // Update controls visibility | 	            // Update controls visibility | ||||||
| 	            ui.toggleControls.call(_this3); | 	            ui.toggleControls.call(_this4); | ||||||
| 	        }, this.loading ? 250 : 0); | 	        }, this.loading ? 250 : 0); | ||||||
| 	    }, | 	    }, | ||||||
|  |  | ||||||
| @ -12511,9 +12520,6 @@ typeof navigator === "object" && (function (global, factory) { | |||||||
| 	            wrap$2(this.media, this.elements.container); | 	            wrap$2(this.media, this.elements.container); | ||||||
| 	        } | 	        } | ||||||
|  |  | ||||||
| 	        // Allow focus to be captured |  | ||||||
| 	        this.elements.container.setAttribute('tabindex', 0); |  | ||||||
|  |  | ||||||
| 	        // Add style hook | 	        // Add style hook | ||||||
| 	        ui.addStyleHook.call(this); | 	        ui.addStyleHook.call(this); | ||||||
|  |  | ||||||
|  | |||||||
							
								
								
									
										2
									
								
								dist/plyr.polyfilled.js.map
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								dist/plyr.polyfilled.js.map
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								dist/plyr.polyfilled.min.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								dist/plyr.polyfilled.min.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								dist/plyr.polyfilled.min.js.map
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								dist/plyr.polyfilled.min.js.map
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @ -15,7 +15,6 @@ import { | |||||||
|     insertAfter, |     insertAfter, | ||||||
|     removeElement, |     removeElement, | ||||||
|     toggleClass, |     toggleClass, | ||||||
|     toggleState, |  | ||||||
| } from './utils/elements'; | } from './utils/elements'; | ||||||
| import { on, triggerEvent } from './utils/events'; | import { on, triggerEvent } from './utils/events'; | ||||||
| import fetch from './utils/fetch'; | import fetch from './utils/fetch'; | ||||||
| @ -193,7 +192,7 @@ const captions = { | |||||||
|             } |             } | ||||||
|  |  | ||||||
|             // Toggle state |             // Toggle state | ||||||
|             toggleState(this.elements.buttons.captions, active); |             this.elements.buttons.captions.pressed = active; | ||||||
|  |  | ||||||
|             // Add class hook |             // Add class hook | ||||||
|             toggleClass(this.elements.container, activeClass, active); |             toggleClass(this.elements.container, activeClass, active); | ||||||
|  | |||||||
| @ -18,6 +18,10 @@ const defaults = { | |||||||
|     // Only allow one media playing at once (vimeo only) |     // Only allow one media playing at once (vimeo only) | ||||||
|     autopause: true, |     autopause: true, | ||||||
|  |  | ||||||
|  |     // Allow inline playback on iOS (this effects YouTube/Vimeo - HTML5 requires the attribute present) | ||||||
|  |     // TODO: Remove iosNative fullscreen option in favour of this (logic needs work) | ||||||
|  |     playsinline: true, | ||||||
|  |  | ||||||
|     // Default time to skip when rewind/fast forward |     // Default time to skip when rewind/fast forward | ||||||
|     seekTime: 10, |     seekTime: 10, | ||||||
|  |  | ||||||
| @ -153,6 +157,7 @@ const defaults = { | |||||||
|         pause: 'Pause', |         pause: 'Pause', | ||||||
|         fastForward: 'Forward {seektime}s', |         fastForward: 'Forward {seektime}s', | ||||||
|         seek: 'Seek', |         seek: 'Seek', | ||||||
|  |         seekLabel: '{currentTime} of {duration}', | ||||||
|         played: 'Played', |         played: 'Played', | ||||||
|         buffered: 'Buffered', |         buffered: 'Buffered', | ||||||
|         currentTime: 'Current time', |         currentTime: 'Current time', | ||||||
| @ -167,6 +172,7 @@ const defaults = { | |||||||
|         frameTitle: 'Player for {title}', |         frameTitle: 'Player for {title}', | ||||||
|         captions: 'Captions', |         captions: 'Captions', | ||||||
|         settings: 'Settings', |         settings: 'Settings', | ||||||
|  |         menuBack: 'Go back to previous menu', | ||||||
|         speed: 'Speed', |         speed: 'Speed', | ||||||
|         normal: 'Normal', |         normal: 'Normal', | ||||||
|         quality: 'Quality', |         quality: 'Quality', | ||||||
| @ -334,6 +340,7 @@ const defaults = { | |||||||
|         posterEnabled: 'plyr__poster-enabled', |         posterEnabled: 'plyr__poster-enabled', | ||||||
|         ads: 'plyr__ads', |         ads: 'plyr__ads', | ||||||
|         control: 'plyr__control', |         control: 'plyr__control', | ||||||
|  |         controlPressed: 'plyr__control--pressed', | ||||||
|         playing: 'plyr--playing', |         playing: 'plyr--playing', | ||||||
|         paused: 'plyr--paused', |         paused: 'plyr--paused', | ||||||
|         stopped: 'plyr--stopped', |         stopped: 'plyr--stopped', | ||||||
|  | |||||||
							
								
								
									
										102
									
								
								src/js/controls.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										102
									
								
								src/js/controls.js
									
									
									
									
										vendored
									
									
								
							| @ -20,7 +20,7 @@ import { | |||||||
|     setAttributes, |     setAttributes, | ||||||
|     toggleClass, |     toggleClass, | ||||||
|     toggleHidden, |     toggleHidden, | ||||||
|     toggleState, |     matches, | ||||||
| } from './utils/elements'; | } from './utils/elements'; | ||||||
| import { off, on } from './utils/events'; | import { off, on } from './utils/events'; | ||||||
| import is from './utils/is'; | import is from './utils/is'; | ||||||
| @ -29,6 +29,7 @@ import { extend } from './utils/objects'; | |||||||
| import { getPercentage, replaceAll, toCamelCase, toTitleCase } from './utils/strings'; | import { getPercentage, replaceAll, toCamelCase, toTitleCase } from './utils/strings'; | ||||||
| import { formatTime, getHours } from './utils/time'; | import { formatTime, getHours } from './utils/time'; | ||||||
|  |  | ||||||
|  | // TODO: Don't export a massive object - break down and create class | ||||||
| const controls = { | const controls = { | ||||||
|     // Get icon URL |     // Get icon URL | ||||||
|     getIconUrl() { |     getIconUrl() { | ||||||
| @ -41,8 +42,7 @@ const controls = { | |||||||
|         }; |         }; | ||||||
|     }, |     }, | ||||||
|  |  | ||||||
|     // Find the UI controls and store references in custom controls |     // Find the UI controls | ||||||
|     // TODO: Allow settings menus with custom controls |  | ||||||
|     findElements() { |     findElements() { | ||||||
|         try { |         try { | ||||||
|             this.elements.controls = getElement.call(this, this.config.selectors.controls.wrapper); |             this.elements.controls = getElement.call(this, this.config.selectors.controls.wrapper); | ||||||
| @ -139,12 +139,11 @@ const controls = { | |||||||
|             pip: 'PIP', |             pip: 'PIP', | ||||||
|             airplay: 'AirPlay', |             airplay: 'AirPlay', | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
|         const text = universals[type] || i18n.get(type, this.config); |         const text = universals[type] || i18n.get(type, this.config); | ||||||
|  |  | ||||||
|         const attributes = Object.assign({}, attr, { |         const attributes = Object.assign({}, attr, { | ||||||
|             class: [attr.class, this.config.classNames.hidden].filter(Boolean).join(' '), |             class: [attr.class, this.config.classNames.hidden].filter(Boolean).join(' '), | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         return createElement('span', attributes, text); |         return createElement('span', attributes, text); | ||||||
|     }, |     }, | ||||||
|  |  | ||||||
| @ -250,9 +249,6 @@ const controls = { | |||||||
|             // Label/Tooltip |             // Label/Tooltip | ||||||
|             button.appendChild(controls.createLabel.call(this, labelPressed, { class: 'label--pressed' })); |             button.appendChild(controls.createLabel.call(this, labelPressed, { class: 'label--pressed' })); | ||||||
|             button.appendChild(controls.createLabel.call(this, label, { class: 'label--not-pressed' })); |             button.appendChild(controls.createLabel.call(this, label, { class: 'label--not-pressed' })); | ||||||
|  |  | ||||||
|             // Add aria attributes |  | ||||||
|             attributes['aria-pressed'] = false; |  | ||||||
|         } else { |         } else { | ||||||
|             button.appendChild(controls.createIcon.call(this, icon)); |             button.appendChild(controls.createIcon.call(this, icon)); | ||||||
|             button.appendChild(controls.createLabel.call(this, label)); |             button.appendChild(controls.createLabel.call(this, label)); | ||||||
| @ -274,22 +270,23 @@ const controls = { | |||||||
|             this.elements.buttons[type] = button; |             this.elements.buttons[type] = button; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         // Toggle classname when pressed property is set | ||||||
|  |         const className = this.config.classNames.controlPressed; | ||||||
|  |         Object.defineProperty(button, 'pressed', { | ||||||
|  |             enumerable: true, | ||||||
|  |             get() { | ||||||
|  |                 return hasClass(button, className); | ||||||
|  |             }, | ||||||
|  |             set(pressed = false) { | ||||||
|  |                 toggleClass(button, className, pressed); | ||||||
|  |             }, | ||||||
|  |         }); | ||||||
|  |  | ||||||
|         return button; |         return button; | ||||||
|     }, |     }, | ||||||
|  |  | ||||||
|     // Create an <input type='range'> |     // Create an <input type='range'> | ||||||
|     createRange(type, attributes) { |     createRange(type, attributes) { | ||||||
|         // Seek label |  | ||||||
|         const label = createElement( |  | ||||||
|             'label', |  | ||||||
|             { |  | ||||||
|                 for: attributes.id, |  | ||||||
|                 id: `${attributes.id}-label`, |  | ||||||
|                 class: this.config.classNames.hidden, |  | ||||||
|             }, |  | ||||||
|             i18n.get(type, this.config), |  | ||||||
|         ); |  | ||||||
|  |  | ||||||
|         // Seek input |         // Seek input | ||||||
|         const input = createElement( |         const input = createElement( | ||||||
|             'input', |             'input', | ||||||
| @ -304,7 +301,7 @@ const controls = { | |||||||
|                     autocomplete: 'off', |                     autocomplete: 'off', | ||||||
|                     // A11y fixes for https://github.com/sampotts/plyr/issues/905 |                     // A11y fixes for https://github.com/sampotts/plyr/issues/905 | ||||||
|                     role: 'slider', |                     role: 'slider', | ||||||
|                     'aria-labelledby': `${attributes.id}-label`, |                     'aria-label': i18n.get(type, this.config), | ||||||
|                     'aria-valuemin': 0, |                     'aria-valuemin': 0, | ||||||
|                     'aria-valuemax': 100, |                     'aria-valuemax': 100, | ||||||
|                     'aria-valuenow': 0, |                     'aria-valuenow': 0, | ||||||
| @ -318,10 +315,7 @@ const controls = { | |||||||
|         // Set the fill for webkit now |         // Set the fill for webkit now | ||||||
|         controls.updateRangeFill.call(this, input); |         controls.updateRangeFill.call(this, input); | ||||||
|  |  | ||||||
|         return { |         return input; | ||||||
|             label, |  | ||||||
|             input, |  | ||||||
|         }; |  | ||||||
|     }, |     }, | ||||||
|  |  | ||||||
|     // Create a <progress> |     // Create a <progress> | ||||||
| @ -349,7 +343,6 @@ const controls = { | |||||||
|                 played: 'played', |                 played: 'played', | ||||||
|                 buffer: 'buffered', |                 buffer: 'buffered', | ||||||
|             }[type]; |             }[type]; | ||||||
|  |  | ||||||
|             const suffix = suffixKey ? i18n.get(suffixKey, this.config) : ''; |             const suffix = suffixKey ? i18n.get(suffixKey, this.config) : ''; | ||||||
|  |  | ||||||
|             progress.innerText = `% ${suffix.toLowerCase()}`; |             progress.innerText = `% ${suffix.toLowerCase()}`; | ||||||
| @ -412,6 +405,19 @@ const controls = { | |||||||
|         list.appendChild(item); |         list.appendChild(item); | ||||||
|     }, |     }, | ||||||
|  |  | ||||||
|  |     // Format a time for display | ||||||
|  |     formatTime(time = 0, inverted = false) { | ||||||
|  |         // Bail if the value isn't a number | ||||||
|  |         if (!is.number(time)) { | ||||||
|  |             return time; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Always display hours if duration is over an hour | ||||||
|  |         const forceHours = getHours(this.duration) > 0; | ||||||
|  |  | ||||||
|  |         return formatTime(time, forceHours, inverted); | ||||||
|  |     }, | ||||||
|  |  | ||||||
|     // Update the displayed time |     // Update the displayed time | ||||||
|     updateTimeDisplay(target = null, time = 0, inverted = false) { |     updateTimeDisplay(target = null, time = 0, inverted = false) { | ||||||
|         // Bail if there's no element to display or the value isn't a number |         // Bail if there's no element to display or the value isn't a number | ||||||
| @ -419,11 +425,8 @@ const controls = { | |||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // Always display hours if duration is over an hour |  | ||||||
|         const forceHours = getHours(this.duration) > 0; |  | ||||||
|  |  | ||||||
|         // eslint-disable-next-line no-param-reassign |         // eslint-disable-next-line no-param-reassign | ||||||
|         target.innerText = formatTime(time, forceHours, inverted); |         target.innerText = controls.formatTime(time, inverted); | ||||||
|     }, |     }, | ||||||
|  |  | ||||||
|     // Update volume UI and storage |     // Update volume UI and storage | ||||||
| @ -439,7 +442,7 @@ const controls = { | |||||||
|  |  | ||||||
|         // Update mute state |         // Update mute state | ||||||
|         if (is.element(this.elements.buttons.mute)) { |         if (is.element(this.elements.buttons.mute)) { | ||||||
|             toggleState(this.elements.buttons.mute, this.muted || this.volume === 0); |             this.elements.buttons.mute.pressed = this.muted || this.volume === 0; | ||||||
|         } |         } | ||||||
|     }, |     }, | ||||||
|  |  | ||||||
| @ -518,8 +521,23 @@ const controls = { | |||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // Set aria value for https://github.com/sampotts/plyr/issues/905 |         // Set aria values for https://github.com/sampotts/plyr/issues/905 | ||||||
|  |         if (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 (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); |             range.setAttribute('aria-valuenow', range.value); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         // WebKit only |         // WebKit only | ||||||
|         if (!browser.isWebkit) { |         if (!browser.isWebkit) { | ||||||
| @ -610,11 +628,16 @@ const controls = { | |||||||
|  |  | ||||||
|     // Show the duration on metadataloaded or durationchange events |     // Show the duration on metadataloaded or durationchange events | ||||||
|     durationUpdate() { |     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)) { |         if (!this.supported.ui || (!this.config.invertTime && this.currentTime)) { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         // Update ARIA values | ||||||
|  |         if (is.element(this.elements.inputs.seek)) { | ||||||
|  |             this.elements.inputs.seek.setAttribute('aria-valuemax', this.duration); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         // If there's a spot to display duration |         // If there's a spot to display duration | ||||||
|         const hasDuration = is.element(this.elements.display.duration); |         const hasDuration = is.element(this.elements.display.duration); | ||||||
|  |  | ||||||
| @ -1117,11 +1140,11 @@ const controls = { | |||||||
|             const progress = createElement('div', getAttributesFromSelector(this.config.selectors.progress)); |             const progress = createElement('div', getAttributesFromSelector(this.config.selectors.progress)); | ||||||
|  |  | ||||||
|             // Seek range slider |             // Seek range slider | ||||||
|             const seek = controls.createRange.call(this, 'seek', { |             progress.appendChild( | ||||||
|  |                 controls.createRange.call(this, 'seek', { | ||||||
|                     id: `plyr-seek-${data.id}`, |                     id: `plyr-seek-${data.id}`, | ||||||
|             }); |                 }), | ||||||
|             progress.appendChild(seek.label); |             ); | ||||||
|             progress.appendChild(seek.input); |  | ||||||
|  |  | ||||||
|             // Buffer progress |             // Buffer progress | ||||||
|             progress.appendChild(controls.createProgress.call(this, 'buffer')); |             progress.appendChild(controls.createProgress.call(this, 'buffer')); | ||||||
| @ -1175,15 +1198,15 @@ const controls = { | |||||||
|             }; |             }; | ||||||
|  |  | ||||||
|             // Create the volume range slider |             // Create the volume range slider | ||||||
|             const range = controls.createRange.call( |             volume.appendChild( | ||||||
|  |                 controls.createRange.call( | ||||||
|                     this, |                     this, | ||||||
|                     'volume', |                     'volume', | ||||||
|                     extend(attributes, { |                     extend(attributes, { | ||||||
|                         id: `plyr-volume-${data.id}`, |                         id: `plyr-volume-${data.id}`, | ||||||
|                     }), |                     }), | ||||||
|  |                 ), | ||||||
|             ); |             ); | ||||||
|             volume.appendChild(range.label); |  | ||||||
|             volume.appendChild(range.input); |  | ||||||
|  |  | ||||||
|             this.elements.volume = volume; |             this.elements.volume = volume; | ||||||
|  |  | ||||||
| @ -1448,7 +1471,6 @@ const controls = { | |||||||
|             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); | ||||||
|                 label.setAttribute('role', 'tooltip'); |  | ||||||
|             }); |             }); | ||||||
|         } |         } | ||||||
|     }, |     }, | ||||||
|  | |||||||
| @ -4,7 +4,7 @@ | |||||||
| // ========================================================================== | // ========================================================================== | ||||||
|  |  | ||||||
| import browser from './utils/browser'; | import browser from './utils/browser'; | ||||||
| import { hasClass, toggleClass, toggleState, trapFocus } from './utils/elements'; | import { hasClass, toggleClass, trapFocus } 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'; | ||||||
|  |  | ||||||
| @ -16,7 +16,7 @@ function onChange() { | |||||||
|     // Update toggle button |     // Update toggle button | ||||||
|     const button = this.player.elements.buttons.fullscreen; |     const button = this.player.elements.buttons.fullscreen; | ||||||
|     if (is.element(button)) { |     if (is.element(button)) { | ||||||
|         toggleState(button, this.active); |         button.pressed = this.active; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // Trigger an event |     // Trigger an event | ||||||
|  | |||||||
| @ -263,9 +263,6 @@ class Plyr { | |||||||
|             wrap(this.media, this.elements.container); |             wrap(this.media, this.elements.container); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // Allow focus to be captured |  | ||||||
|         this.elements.container.setAttribute('tabindex', 0); |  | ||||||
|  |  | ||||||
|         // Add style hook |         // Add style hook | ||||||
|         ui.addStyleHook.call(this); |         ui.addStyleHook.call(this); | ||||||
|  |  | ||||||
|  | |||||||
							
								
								
									
										11
									
								
								src/js/ui.js
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								src/js/ui.js
									
									
									
									
									
								
							| @ -7,7 +7,7 @@ import controls from './controls'; | |||||||
| import i18n from './i18n'; | import i18n from './i18n'; | ||||||
| import support from './support'; | import support from './support'; | ||||||
| import browser from './utils/browser'; | import browser from './utils/browser'; | ||||||
| import { getElement, toggleClass, toggleState } from './utils/elements'; | import { getElement, toggleClass } from './utils/elements'; | ||||||
| import { ready, triggerEvent } from './utils/events'; | import { ready, triggerEvent } from './utils/events'; | ||||||
| import is from './utils/is'; | import is from './utils/is'; | ||||||
| import loadImage from './utils/loadImage'; | import loadImage from './utils/loadImage'; | ||||||
| @ -132,9 +132,6 @@ const ui = { | |||||||
|         // If there's a media title set, use that for the label |         // If there's a media title set, use that for the label | ||||||
|         if (is.string(this.config.title) && !is.empty(this.config.title)) { |         if (is.string(this.config.title) && !is.empty(this.config.title)) { | ||||||
|             label += `, ${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 |         // If there's a play button, set label | ||||||
| @ -216,8 +213,10 @@ const ui = { | |||||||
|         toggleClass(this.elements.container, this.config.classNames.paused, this.paused); |         toggleClass(this.elements.container, this.config.classNames.paused, this.paused); | ||||||
|         toggleClass(this.elements.container, this.config.classNames.stopped, this.stopped); |         toggleClass(this.elements.container, this.config.classNames.stopped, this.stopped); | ||||||
|  |  | ||||||
|         // Set ARIA state |         // Set state | ||||||
|         toggleState(this.elements.buttons.play, this.playing); |         Array.from(this.elements.buttons.play).forEach(target => { | ||||||
|  |             target.pressed = this.playing; | ||||||
|  |         }); | ||||||
|  |  | ||||||
|         // Only update controls on non timeupdate events |         // Only update controls on non timeupdate events | ||||||
|         if (is.event(event) && event.type === 'timeupdate') { |         if (is.event(event) && event.type === 'timeupdate') { | ||||||
|  | |||||||
| @ -283,25 +283,3 @@ export function trapFocus(element = null, toggle = false) { | |||||||
|  |  | ||||||
|     toggleListener.call(this, this.elements.container, 'keydown', trap, toggle, false); |     toggleListener.call(this, this.elements.container, 'keydown', trap, toggle, false); | ||||||
| } | } | ||||||
|  |  | ||||||
| // Toggle aria-pressed state on a toggle button |  | ||||||
| // http://www.ssbbartgroup.com/blog/how-not-to-misuse-aria-states-properties-and-roles |  | ||||||
| export function toggleState(element, input) { |  | ||||||
|     // If multiple elements passed |  | ||||||
|     if (is.array(element) || is.nodeList(element)) { |  | ||||||
|         Array.from(element).forEach(target => toggleState(target, input)); |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // Bail if no target |  | ||||||
|     if (!is.element(element)) { |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // Get state |  | ||||||
|     const pressed = element.getAttribute('aria-pressed') === 'true'; |  | ||||||
|     const state = is.boolean(input) ? input : !pressed; |  | ||||||
|  |  | ||||||
|     // Set the attribute on target |  | ||||||
|     element.setAttribute('aria-pressed', state); |  | ||||||
| } |  | ||||||
|  | |||||||
| @ -32,5 +32,5 @@ export function formatTime(time = 0, displayHours = false, inverted = false) { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     // Render |     // Render | ||||||
|     return `${inverted ? '-' : ''}${hours}${format(mins)}:${format(secs)}`; |     return `${inverted && time > 0 ? '-' : ''}${hours}${format(mins)}:${format(secs)}`; | ||||||
| } | } | ||||||
|  | |||||||
| @ -34,10 +34,10 @@ | |||||||
| } | } | ||||||
|  |  | ||||||
| // Change icons on state change | // Change icons on state change | ||||||
| .plyr__control[aria-pressed='false'] .icon--pressed, | .plyr__control:not(.plyr__control--pressed) .icon--pressed, | ||||||
| .plyr__control[aria-pressed='true'] .icon--not-pressed, | .plyr__control.plyr__control--pressed .icon--not-pressed, | ||||||
| .plyr__control[aria-pressed='false'] .label--pressed, | .plyr__control:not(.plyr__control--pressed) .label--pressed, | ||||||
| .plyr__control[aria-pressed='true'] .label--not-pressed { | .plyr__control.plyr__control--pressed .label--not-pressed { | ||||||
|     display: none; |     display: none; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user