10
									
								
								.github/pull_request_template.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								.github/pull_request_template.md
									
									
									
									
										vendored
									
									
								
							| @ -1,8 +1,8 @@ | ||||
| ### Link to related issue (if applicable) | ||||
|  | ||||
| ### Sumary of proposed changes | ||||
| ### Summary of proposed changes | ||||
|  | ||||
| ### Task list | ||||
|  | ||||
| - [ ] Tested on [supported browsers](https://github.com/sampotts/plyr#browser-support) | ||||
| - [ ] Gulp build completed | ||||
| ### Checklist | ||||
| - [ ] Use `develop` as the base branch | ||||
| - [ ] Exclude the gulp build from the PR | ||||
| - [ ] Test on [supported browsers](https://github.com/sampotts/plyr#browser-support) | ||||
|  | ||||
							
								
								
									
										7
									
								
								.travis.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								.travis.yml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| language: node_js | ||||
| node_js: | ||||
|   - 'lts/*' | ||||
|  | ||||
| script: | ||||
|   - npm run lint | ||||
|   - npm run build | ||||
							
								
								
									
										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
											
										
									
								
							
							
								
								
									
										221
									
								
								dist/plyr.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										221
									
								
								dist/plyr.js
									
									
									
									
										vendored
									
									
								
							| @ -1300,6 +1300,14 @@ var utils = { | ||||
|     }, | ||||
|  | ||||
|  | ||||
|     // Get a nested value in an object | ||||
|     getDeep: function getDeep(object, path) { | ||||
|         return path.split('.').reduce(function (obj, key) { | ||||
|             return obj && obj[key]; | ||||
|         }, object); | ||||
|     }, | ||||
|  | ||||
|  | ||||
|     // Get the closest value in an array | ||||
|     closest: function closest(array, value) { | ||||
|         if (!utils.is.array(array) || !array.length) { | ||||
| @ -1719,6 +1727,13 @@ var html5 = { | ||||
|  | ||||
|                 player.media.src = supported[0].getAttribute('src'); | ||||
|  | ||||
|                 // Restore time | ||||
|                 var onLoadedMetaData = function onLoadedMetaData() { | ||||
|                     player.currentTime = currentTime; | ||||
|                     player.off('loadedmetadata', onLoadedMetaData); | ||||
|                 }; | ||||
|                 player.on('loadedmetadata', onLoadedMetaData); | ||||
|  | ||||
|                 // Load new source | ||||
|                 player.media.load(); | ||||
|  | ||||
| @ -1727,9 +1742,6 @@ var html5 = { | ||||
|                     player.play(); | ||||
|                 } | ||||
|  | ||||
|                 // Restore time | ||||
|                 player.currentTime = currentTime; | ||||
|  | ||||
|                 // Trigger change event | ||||
|                 utils.dispatchEvent.call(player, player.media, 'qualitychange', false, { | ||||
|                     quality: input | ||||
| @ -1771,11 +1783,15 @@ var i18n = { | ||||
|         var key = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; | ||||
|         var config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||||
|  | ||||
|         if (utils.is.empty(key) || utils.is.empty(config) || !Object.keys(config.i18n).includes(key)) { | ||||
|         if (utils.is.empty(key) || utils.is.empty(config)) { | ||||
|             return ''; | ||||
|         } | ||||
|  | ||||
|         var string = config.i18n[key]; | ||||
|         var string = utils.getDeep(config.i18n, key); | ||||
|  | ||||
|         if (utils.is.empty(string)) { | ||||
|             return ''; | ||||
|         } | ||||
|  | ||||
|         var replace = { | ||||
|             '{seektime}': config.seekTime, | ||||
| @ -2449,27 +2465,7 @@ var controls = { | ||||
|  | ||||
|         // Get the badge HTML for HD, 4K etc | ||||
|         var getBadge = function getBadge(quality) { | ||||
|             var label = ''; | ||||
|  | ||||
|             switch (quality) { | ||||
|                 case 2160: | ||||
|                     label = '4K'; | ||||
|                     break; | ||||
|  | ||||
|                 case 1440: | ||||
|                 case 1080: | ||||
|                 case 720: | ||||
|                     label = 'HD'; | ||||
|                     break; | ||||
|  | ||||
|                 case 576: | ||||
|                 case 480: | ||||
|                     label = 'SD'; | ||||
|                     break; | ||||
|  | ||||
|                 default: | ||||
|                     break; | ||||
|             } | ||||
|             var label = i18n.get('qualityBadge.' + quality, _this3.config); | ||||
|  | ||||
|             if (!label.length) { | ||||
|                 return null; | ||||
| @ -2492,7 +2488,6 @@ var controls = { | ||||
|  | ||||
|  | ||||
|     // Translate a value into a nice label | ||||
|     // TODO: Localisation | ||||
|     getLabel: function getLabel(setting, value) { | ||||
|         switch (setting) { | ||||
|             case 'speed': | ||||
| @ -2500,7 +2495,13 @@ var controls = { | ||||
|  | ||||
|             case 'quality': | ||||
|                 if (utils.is.number(value)) { | ||||
|                     return value + 'p'; | ||||
|                     var label = i18n.get('qualityLabel.' + value, this.config); | ||||
|  | ||||
|                     if (!label.length) { | ||||
|                         return value + 'p'; | ||||
|                     } | ||||
|  | ||||
|                     return label; | ||||
|                 } | ||||
|  | ||||
|                 return utils.toTitleCase(value); | ||||
| @ -2660,12 +2661,7 @@ var controls = { | ||||
|  | ||||
|         // Generate options | ||||
|         tracks.forEach(function (track) { | ||||
|             controls.createMenuItem.call(_this4, track.language, list, 'language', track.label, track.language !== 'enabled' ? controls.createBadge.call(_this4, track.language.toUpperCase()) : null, track.language.toLowerCase() === _this4.captions.language.toLowerCase()); | ||||
|         }); | ||||
|  | ||||
|         // Store reference | ||||
|         this.options.captions = tracks.map(function (track) { | ||||
|             return track.language; | ||||
|             controls.createMenuItem.call(_this4, track.language, list, 'language', track.label, track.language !== 'enabled' ? controls.createBadge.call(_this4, track.language.toUpperCase()) : null, track.language.toLowerCase() === _this4.language); | ||||
|         }); | ||||
|  | ||||
|         controls.updateSetting.call(this, type, list); | ||||
| @ -3268,28 +3264,6 @@ var captions = { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         // Set default language if not set | ||||
|         var stored = this.storage.get('language'); | ||||
|  | ||||
|         if (!utils.is.empty(stored)) { | ||||
|             this.captions.language = stored; | ||||
|         } | ||||
|  | ||||
|         if (utils.is.empty(this.captions.language)) { | ||||
|             this.captions.language = this.config.captions.language.toLowerCase(); | ||||
|         } | ||||
|  | ||||
|         // Set captions enabled state if not set | ||||
|         if (!utils.is.boolean(this.captions.active)) { | ||||
|             var active = this.storage.get('captions'); | ||||
|  | ||||
|             if (utils.is.boolean(active)) { | ||||
|                 this.captions.active = active; | ||||
|             } else { | ||||
|                 this.captions.active = this.config.captions.active; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Only Vimeo and HTML5 video supported at this point | ||||
|         if (!this.isVideo || this.isYouTube || this.isHTML5 && !support.textTracks) { | ||||
|             // Clear menu and hide | ||||
| @ -3307,17 +3281,6 @@ var captions = { | ||||
|             utils.insertAfter(this.elements.captions, this.elements.wrapper); | ||||
|         } | ||||
|  | ||||
|         // Set the class hook | ||||
|         utils.toggleClass(this.elements.container, this.config.classNames.captions.enabled, !utils.is.empty(captions.getTracks.call(this))); | ||||
|  | ||||
|         // Get tracks | ||||
|         var tracks = captions.getTracks.call(this); | ||||
|  | ||||
|         // If no caption file exists, hide container for caption text | ||||
|         if (utils.is.empty(tracks)) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         // Get browser info | ||||
|         var browser = utils.getBrowser(); | ||||
|  | ||||
| @ -3340,14 +3303,52 @@ var captions = { | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         // Set language | ||||
|         captions.setLanguage.call(this); | ||||
|         // Try to load the value from storage | ||||
|         var active = this.storage.get('captions'); | ||||
|  | ||||
|         // Enable UI | ||||
|         captions.show.call(this); | ||||
|         // Otherwise fall back to the default config | ||||
|         if (!utils.is.boolean(active)) { | ||||
|             active = this.config.captions.active; | ||||
|         } | ||||
|  | ||||
|         // Set available languages in list | ||||
|         if (utils.is.array(this.config.controls) && this.config.controls.includes('settings') && this.config.settings.includes('captions')) { | ||||
|         // Set toggled state | ||||
|         this.toggleCaptions(active); | ||||
|  | ||||
|         // Watch changes to textTracks and update captions menu | ||||
|         if (this.config.captions.update) { | ||||
|             utils.on(this.media.textTracks, 'addtrack removetrack', captions.update.bind(this)); | ||||
|         } | ||||
|  | ||||
|         // Update available languages in list next tick (the event must not be triggered before the listeners) | ||||
|         setTimeout(captions.update.bind(this), 0); | ||||
|     }, | ||||
|     update: function update() { | ||||
|         // Update tracks | ||||
|         var tracks = captions.getTracks.call(this); | ||||
|         this.options.captions = tracks.map(function (_ref) { | ||||
|             var language = _ref.language; | ||||
|             return language; | ||||
|         }); | ||||
|  | ||||
|         // Set language if it hasn't been set already | ||||
|         if (!this.language) { | ||||
|             var language = this.config.captions.language; | ||||
|  | ||||
|             if (language === 'auto') { | ||||
|                 var _split = (navigator.language || navigator.userLanguage).split('-'); | ||||
|  | ||||
|                 var _split2 = slicedToArray(_split, 1); | ||||
|  | ||||
|                 language = _split2[0]; | ||||
|             } | ||||
|             this.language = this.storage.get('language') || (language || '').toLowerCase(); | ||||
|         } | ||||
|  | ||||
|         // Toggle the class hooks | ||||
|         utils.toggleClass(this.elements.container, this.config.classNames.captions.enabled, !utils.is.empty(captions.getTracks.call(this))); | ||||
|  | ||||
|         // Update available languages in list | ||||
|         if ((this.config.controls || []).includes('settings') && this.config.settings.includes('captions')) { | ||||
|             controls.setCaptionsMenu.call(this); | ||||
|         } | ||||
|     }, | ||||
| @ -3508,25 +3509,6 @@ var captions = { | ||||
|         } else { | ||||
|             this.debug.warn('No captions element to render to'); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|  | ||||
|     // Display captions container and button (for initialization) | ||||
|     show: function show() { | ||||
|         // Try to load the value from storage | ||||
|         var active = this.storage.get('captions'); | ||||
|  | ||||
|         // Otherwise fall back to the default config | ||||
|         if (!utils.is.boolean(active)) { | ||||
|             active = this.config.captions.active; | ||||
|         } else { | ||||
|             this.captions.active = active; | ||||
|         } | ||||
|  | ||||
|         if (active) { | ||||
|             utils.toggleClass(this.elements.container, this.config.classNames.captions.active, true); | ||||
|             utils.toggleState(this.elements.buttons.captions, true); | ||||
|         } | ||||
|     } | ||||
| }; | ||||
|  | ||||
| @ -3667,7 +3649,10 @@ var defaults$1 = { | ||||
|     // Captions settings | ||||
|     captions: { | ||||
|         active: false, | ||||
|         language: (navigator.language || navigator.userLanguage).split('-')[0] | ||||
|         language: 'auto', | ||||
|         // Listen to new tracks added after Plyr is initialized. | ||||
|         // This is needed for streaming captions, but may result in unselectable options | ||||
|         update: false | ||||
|     }, | ||||
|  | ||||
|     // Fullscreen settings | ||||
| @ -3724,7 +3709,15 @@ var defaults$1 = { | ||||
|         reset: 'Reset', | ||||
|         disabled: 'Disabled', | ||||
|         enabled: 'Enabled', | ||||
|         advertisement: 'Ad' | ||||
|         advertisement: 'Ad', | ||||
|         qualityBadge: { | ||||
|             2160: '4K', | ||||
|             1440: 'HD', | ||||
|             1080: 'HD', | ||||
|             720: 'HD', | ||||
|             576: 'SD', | ||||
|             480: 'SD' | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     // URLs | ||||
| @ -3812,9 +3805,8 @@ var defaults$1 = { | ||||
|         display: { | ||||
|             currentTime: '.plyr__time--current', | ||||
|             duration: '.plyr__time--duration', | ||||
|             buffer: '.plyr__progress--buffer', | ||||
|             played: '.plyr__progress--played', | ||||
|             loop: '.plyr__progress--loop', | ||||
|             buffer: '.plyr__progress__buffer', | ||||
|             loop: '.plyr__progress__loop', // Used later | ||||
|             volume: '.plyr__volume--display' | ||||
|         }, | ||||
|         progress: '.plyr__progress', | ||||
| @ -4183,8 +4175,10 @@ var ui = { | ||||
|         // Remove native controls | ||||
|         ui.toggleNativeControls.call(this); | ||||
|  | ||||
|         // Captions | ||||
|         captions.setup.call(this); | ||||
|         // Setup captions for HTML5 | ||||
|         if (this.isHTML5) { | ||||
|             captions.setup.call(this); | ||||
|         } | ||||
|  | ||||
|         // Reset volume | ||||
|         this.volume = null; | ||||
| @ -4237,6 +4231,12 @@ var ui = { | ||||
|         if (this.poster && this.elements.poster && !this.elements.poster.style.backgroundImage) { | ||||
|             ui.setPoster.call(this, this.poster); | ||||
|         } | ||||
|  | ||||
|         // Manually set the duration if user has overridden it. | ||||
|         // The event listeners for it doesn't get called if preload is disabled (#701) | ||||
|         if (this.config.duration) { | ||||
|             controls.durationUpdate.call(this); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|  | ||||
| @ -7294,24 +7294,19 @@ var Plyr = function () { | ||||
|             } | ||||
|  | ||||
|             // If the method is called without parameter, toggle based on current value | ||||
|             var show = utils.is.boolean(input) ? input : !this.elements.container.classList.contains(this.config.classNames.captions.active); | ||||
|  | ||||
|             // Nothing to change... | ||||
|             if (this.captions.active === show) { | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             // Set global | ||||
|             this.captions.active = show; | ||||
|             var active = utils.is.boolean(input) ? input : !this.elements.container.classList.contains(this.config.classNames.captions.active); | ||||
|  | ||||
|             // Toggle state | ||||
|             utils.toggleState(this.elements.buttons.captions, this.captions.active); | ||||
|             utils.toggleState(this.elements.buttons.captions, active); | ||||
|  | ||||
|             // Add class hook | ||||
|             utils.toggleClass(this.elements.container, this.config.classNames.captions.active, this.captions.active); | ||||
|             utils.toggleClass(this.elements.container, this.config.classNames.captions.active, active); | ||||
|  | ||||
|             // Trigger an event | ||||
|             utils.dispatchEvent.call(this, this.media, this.captions.active ? 'captionsenabled' : 'captionsdisabled'); | ||||
|             // Update state and trigger event | ||||
|             if (active !== this.captions.active) { | ||||
|                 this.captions.active = active; | ||||
|                 utils.dispatchEvent.call(this, this.media, this.captions.active ? 'captionsenabled' : 'captionsdisabled'); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         /** | ||||
| @ -7843,7 +7838,7 @@ var Plyr = function () { | ||||
|                 quality = Number(input); | ||||
|             } | ||||
|  | ||||
|             if (!utils.is.number(quality) || quality === 0) { | ||||
|             if (!utils.is.number(quality)) { | ||||
|                 quality = this.storage.get('quality'); | ||||
|             } | ||||
|  | ||||
|  | ||||
							
								
								
									
										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
											
										
									
								
							
							
								
								
									
										275
									
								
								dist/plyr.polyfilled.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										275
									
								
								dist/plyr.polyfilled.js
									
									
									
									
										vendored
									
									
								
							| @ -20,7 +20,7 @@ if (typeof __g == 'number') __g = global; // eslint-disable-line no-undef | ||||
| }); | ||||
|  | ||||
| var _core = createCommonjsModule(function (module) { | ||||
| var core = module.exports = { version: '2.5.6' }; | ||||
| var core = module.exports = { version: '2.5.3' }; | ||||
| if (typeof __e == 'number') __e = core; // eslint-disable-line no-undef | ||||
| }); | ||||
| var _core_1 = _core.version; | ||||
| @ -333,18 +333,11 @@ var _arrayIncludes = function (IS_INCLUDES) { | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| var _shared = createCommonjsModule(function (module) { | ||||
| var SHARED = '__core-js_shared__'; | ||||
| var store = _global[SHARED] || (_global[SHARED] = {}); | ||||
|  | ||||
| (module.exports = function (key, value) { | ||||
|   return store[key] || (store[key] = value !== undefined ? value : {}); | ||||
| })('versions', []).push({ | ||||
|   version: _core.version, | ||||
|   mode: _library ? 'pure' : 'global', | ||||
|   copyright: '© 2018 Denis Pushkarev (zloirock.ru)' | ||||
| }); | ||||
| }); | ||||
| var _shared = function (key) { | ||||
|   return store[key] || (store[key] = {}); | ||||
| }; | ||||
|  | ||||
| var shared = _shared('keys'); | ||||
|  | ||||
| @ -998,7 +991,7 @@ var _iterDefine = function (Base, NAME, Constructor, next, DEFAULT, IS_SET, FORC | ||||
|   var VALUES_BUG = false; | ||||
|   var proto = Base.prototype; | ||||
|   var $native = proto[ITERATOR$2] || proto[FF_ITERATOR] || DEFAULT && proto[DEFAULT]; | ||||
|   var $default = $native || getMethod(DEFAULT); | ||||
|   var $default = (!BUGGY && $native) || getMethod(DEFAULT); | ||||
|   var $entries = DEFAULT ? !DEF_VALUES ? $default : getMethod('entries') : undefined; | ||||
|   var $anyNative = NAME == 'Array' ? proto.entries || $native : $native; | ||||
|   var methods, key, IteratorPrototype; | ||||
| @ -1009,7 +1002,7 @@ var _iterDefine = function (Base, NAME, Constructor, next, DEFAULT, IS_SET, FORC | ||||
|       // Set @@toStringTag to native iterators | ||||
|       _setToStringTag(IteratorPrototype, TAG, true); | ||||
|       // fix for some old engines | ||||
|       if (!_library && typeof IteratorPrototype[ITERATOR$2] != 'function') _hide(IteratorPrototype, ITERATOR$2, returnThis); | ||||
|       if (!_library && !_has(IteratorPrototype, ITERATOR$2)) _hide(IteratorPrototype, ITERATOR$2, returnThis); | ||||
|     } | ||||
|   } | ||||
|   // fix Array#{values, @@iterator}.name in V8 / FF | ||||
| @ -2503,11 +2496,9 @@ function set(target, propertyKey, V /* , receiver */) { | ||||
|   } | ||||
|   if (_has(ownDesc, 'value')) { | ||||
|     if (ownDesc.writable === false || !_isObject(receiver)) return false; | ||||
|     if (existingDescriptor = _objectGopd.f(receiver, propertyKey)) { | ||||
|       if (existingDescriptor.get || existingDescriptor.set || existingDescriptor.writable === false) return false; | ||||
|       existingDescriptor.value = V; | ||||
|       _objectDp.f(receiver, propertyKey, existingDescriptor); | ||||
|     } else _objectDp.f(receiver, propertyKey, _propertyDesc(0, V)); | ||||
|     existingDescriptor = _objectGopd.f(receiver, propertyKey) || _propertyDesc(0); | ||||
|     existingDescriptor.value = V; | ||||
|     _objectDp.f(receiver, propertyKey, existingDescriptor); | ||||
|     return true; | ||||
|   } | ||||
|   return ownDesc.set === undefined ? false : (ownDesc.set.call(receiver, V), true); | ||||
| @ -2652,8 +2643,7 @@ var _microtask = function () { | ||||
|     }; | ||||
|   // environments with maybe non-completely correct, but existent Promise | ||||
|   } else if (Promise$1 && Promise$1.resolve) { | ||||
|     // Promise.resolve without an argument throws an error in LG WebOS 2 | ||||
|     var promise = Promise$1.resolve(undefined); | ||||
|     var promise = Promise$1.resolve(); | ||||
|     notify = function () { | ||||
|       promise.then(flush); | ||||
|     }; | ||||
| @ -2710,10 +2700,6 @@ var _perform = function (exec) { | ||||
|   } | ||||
| }; | ||||
|  | ||||
| var navigator$1 = _global.navigator; | ||||
|  | ||||
| var _userAgent = navigator$1 && navigator$1.userAgent || ''; | ||||
|  | ||||
| var _promiseResolve = function (C, x) { | ||||
|   _anObject(C); | ||||
|   if (_isObject(x) && x.constructor === C) return x; | ||||
| @ -2728,12 +2714,9 @@ var microtask = _microtask(); | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| var PROMISE = 'Promise'; | ||||
| var TypeError$1 = _global.TypeError; | ||||
| var process$2 = _global.process; | ||||
| var versions = process$2 && process$2.versions; | ||||
| var v8 = versions && versions.v8 || ''; | ||||
| var $Promise = _global[PROMISE]; | ||||
| var isNode$1 = _classof(process$2) == 'process'; | ||||
| var empty = function () { /* empty */ }; | ||||
| @ -2748,13 +2731,7 @@ var USE_NATIVE = !!function () { | ||||
|       exec(empty, empty); | ||||
|     }; | ||||
|     // unhandled rejections tracking support, NodeJS Promise without it fails @@species test | ||||
|     return (isNode$1 || typeof PromiseRejectionEvent == 'function') | ||||
|       && promise.then(empty) instanceof FakePromise | ||||
|       // v8 6.6 (Node 10 and Chrome 66) have a bug with resolving custom thenables | ||||
|       // https://bugs.chromium.org/p/chromium/issues/detail?id=830565 | ||||
|       // we can't detect it synchronously, so just check versions | ||||
|       && v8.indexOf('6.6') !== 0 | ||||
|       && _userAgent.indexOf('Chrome/66') === -1; | ||||
|     return (isNode$1 || typeof PromiseRejectionEvent == 'function') && promise.then(empty) instanceof FakePromise; | ||||
|   } catch (e) { /* empty */ } | ||||
| }(); | ||||
|  | ||||
| @ -2776,7 +2753,7 @@ var notify = function (promise, isReject) { | ||||
|       var resolve = reaction.resolve; | ||||
|       var reject = reaction.reject; | ||||
|       var domain = reaction.domain; | ||||
|       var result, then, exited; | ||||
|       var result, then; | ||||
|       try { | ||||
|         if (handler) { | ||||
|           if (!ok) { | ||||
| @ -2786,11 +2763,8 @@ var notify = function (promise, isReject) { | ||||
|           if (handler === true) result = value; | ||||
|           else { | ||||
|             if (domain) domain.enter(); | ||||
|             result = handler(value); // may throw | ||||
|             if (domain) { | ||||
|               domain.exit(); | ||||
|               exited = true; | ||||
|             } | ||||
|             result = handler(value); | ||||
|             if (domain) domain.exit(); | ||||
|           } | ||||
|           if (result === reaction.promise) { | ||||
|             reject(TypeError$1('Promise-chain cycle')); | ||||
| @ -2799,7 +2773,6 @@ var notify = function (promise, isReject) { | ||||
|           } else resolve(result); | ||||
|         } else reject(value); | ||||
|       } catch (e) { | ||||
|         if (domain && !exited) domain.exit(); | ||||
|         reject(e); | ||||
|       } | ||||
|     }; | ||||
| @ -4182,6 +4155,10 @@ var _stringPad = function (that, maxLength, fillString, left) { | ||||
|   return left ? stringFiller + S : S + stringFiller; | ||||
| }; | ||||
|  | ||||
| var navigator$1 = _global.navigator; | ||||
|  | ||||
| var _userAgent = navigator$1 && navigator$1.userAgent || ''; | ||||
|  | ||||
| // https://github.com/tc39/proposal-string-pad-start-end | ||||
|  | ||||
|  | ||||
| @ -6706,6 +6683,14 @@ var utils = { | ||||
|     }, | ||||
|  | ||||
|  | ||||
|     // Get a nested value in an object | ||||
|     getDeep: function getDeep(object, path) { | ||||
|         return path.split('.').reduce(function (obj, key) { | ||||
|             return obj && obj[key]; | ||||
|         }, object); | ||||
|     }, | ||||
|  | ||||
|  | ||||
|     // Get the closest value in an array | ||||
|     closest: function closest(array, value) { | ||||
|         if (!utils.is.array(array) || !array.length) { | ||||
| @ -7125,6 +7110,13 @@ var html5 = { | ||||
|  | ||||
|                 player.media.src = supported[0].getAttribute('src'); | ||||
|  | ||||
|                 // Restore time | ||||
|                 var onLoadedMetaData = function onLoadedMetaData() { | ||||
|                     player.currentTime = currentTime; | ||||
|                     player.off('loadedmetadata', onLoadedMetaData); | ||||
|                 }; | ||||
|                 player.on('loadedmetadata', onLoadedMetaData); | ||||
|  | ||||
|                 // Load new source | ||||
|                 player.media.load(); | ||||
|  | ||||
| @ -7133,9 +7125,6 @@ var html5 = { | ||||
|                     player.play(); | ||||
|                 } | ||||
|  | ||||
|                 // Restore time | ||||
|                 player.currentTime = currentTime; | ||||
|  | ||||
|                 // Trigger change event | ||||
|                 utils.dispatchEvent.call(player, player.media, 'qualitychange', false, { | ||||
|                     quality: input | ||||
| @ -7177,11 +7166,15 @@ var i18n = { | ||||
|         var key = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; | ||||
|         var config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||||
|  | ||||
|         if (utils.is.empty(key) || utils.is.empty(config) || !Object.keys(config.i18n).includes(key)) { | ||||
|         if (utils.is.empty(key) || utils.is.empty(config)) { | ||||
|             return ''; | ||||
|         } | ||||
|  | ||||
|         var string = config.i18n[key]; | ||||
|         var string = utils.getDeep(config.i18n, key); | ||||
|  | ||||
|         if (utils.is.empty(string)) { | ||||
|             return ''; | ||||
|         } | ||||
|  | ||||
|         var replace = { | ||||
|             '{seektime}': config.seekTime, | ||||
| @ -7855,27 +7848,7 @@ var controls = { | ||||
|  | ||||
|         // Get the badge HTML for HD, 4K etc | ||||
|         var getBadge = function getBadge(quality) { | ||||
|             var label = ''; | ||||
|  | ||||
|             switch (quality) { | ||||
|                 case 2160: | ||||
|                     label = '4K'; | ||||
|                     break; | ||||
|  | ||||
|                 case 1440: | ||||
|                 case 1080: | ||||
|                 case 720: | ||||
|                     label = 'HD'; | ||||
|                     break; | ||||
|  | ||||
|                 case 576: | ||||
|                 case 480: | ||||
|                     label = 'SD'; | ||||
|                     break; | ||||
|  | ||||
|                 default: | ||||
|                     break; | ||||
|             } | ||||
|             var label = i18n.get('qualityBadge.' + quality, _this3.config); | ||||
|  | ||||
|             if (!label.length) { | ||||
|                 return null; | ||||
| @ -7898,7 +7871,6 @@ var controls = { | ||||
|  | ||||
|  | ||||
|     // Translate a value into a nice label | ||||
|     // TODO: Localisation | ||||
|     getLabel: function getLabel(setting, value) { | ||||
|         switch (setting) { | ||||
|             case 'speed': | ||||
| @ -7906,7 +7878,13 @@ var controls = { | ||||
|  | ||||
|             case 'quality': | ||||
|                 if (utils.is.number(value)) { | ||||
|                     return value + 'p'; | ||||
|                     var label = i18n.get('qualityLabel.' + value, this.config); | ||||
|  | ||||
|                     if (!label.length) { | ||||
|                         return value + 'p'; | ||||
|                     } | ||||
|  | ||||
|                     return label; | ||||
|                 } | ||||
|  | ||||
|                 return utils.toTitleCase(value); | ||||
| @ -8066,12 +8044,7 @@ var controls = { | ||||
|  | ||||
|         // Generate options | ||||
|         tracks.forEach(function (track) { | ||||
|             controls.createMenuItem.call(_this4, track.language, list, 'language', track.label, track.language !== 'enabled' ? controls.createBadge.call(_this4, track.language.toUpperCase()) : null, track.language.toLowerCase() === _this4.captions.language.toLowerCase()); | ||||
|         }); | ||||
|  | ||||
|         // Store reference | ||||
|         this.options.captions = tracks.map(function (track) { | ||||
|             return track.language; | ||||
|             controls.createMenuItem.call(_this4, track.language, list, 'language', track.label, track.language !== 'enabled' ? controls.createBadge.call(_this4, track.language.toUpperCase()) : null, track.language.toLowerCase() === _this4.language); | ||||
|         }); | ||||
|  | ||||
|         controls.updateSetting.call(this, type, list); | ||||
| @ -8674,28 +8647,6 @@ var captions = { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         // Set default language if not set | ||||
|         var stored = this.storage.get('language'); | ||||
|  | ||||
|         if (!utils.is.empty(stored)) { | ||||
|             this.captions.language = stored; | ||||
|         } | ||||
|  | ||||
|         if (utils.is.empty(this.captions.language)) { | ||||
|             this.captions.language = this.config.captions.language.toLowerCase(); | ||||
|         } | ||||
|  | ||||
|         // Set captions enabled state if not set | ||||
|         if (!utils.is.boolean(this.captions.active)) { | ||||
|             var active = this.storage.get('captions'); | ||||
|  | ||||
|             if (utils.is.boolean(active)) { | ||||
|                 this.captions.active = active; | ||||
|             } else { | ||||
|                 this.captions.active = this.config.captions.active; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Only Vimeo and HTML5 video supported at this point | ||||
|         if (!this.isVideo || this.isYouTube || this.isHTML5 && !support.textTracks) { | ||||
|             // Clear menu and hide | ||||
| @ -8713,17 +8664,6 @@ var captions = { | ||||
|             utils.insertAfter(this.elements.captions, this.elements.wrapper); | ||||
|         } | ||||
|  | ||||
|         // Set the class hook | ||||
|         utils.toggleClass(this.elements.container, this.config.classNames.captions.enabled, !utils.is.empty(captions.getTracks.call(this))); | ||||
|  | ||||
|         // Get tracks | ||||
|         var tracks = captions.getTracks.call(this); | ||||
|  | ||||
|         // If no caption file exists, hide container for caption text | ||||
|         if (utils.is.empty(tracks)) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         // Get browser info | ||||
|         var browser = utils.getBrowser(); | ||||
|  | ||||
| @ -8746,14 +8686,52 @@ var captions = { | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         // Set language | ||||
|         captions.setLanguage.call(this); | ||||
|         // Try to load the value from storage | ||||
|         var active = this.storage.get('captions'); | ||||
|  | ||||
|         // Enable UI | ||||
|         captions.show.call(this); | ||||
|         // Otherwise fall back to the default config | ||||
|         if (!utils.is.boolean(active)) { | ||||
|             active = this.config.captions.active; | ||||
|         } | ||||
|  | ||||
|         // Set available languages in list | ||||
|         if (utils.is.array(this.config.controls) && this.config.controls.includes('settings') && this.config.settings.includes('captions')) { | ||||
|         // Set toggled state | ||||
|         this.toggleCaptions(active); | ||||
|  | ||||
|         // Watch changes to textTracks and update captions menu | ||||
|         if (this.config.captions.update) { | ||||
|             utils.on(this.media.textTracks, 'addtrack removetrack', captions.update.bind(this)); | ||||
|         } | ||||
|  | ||||
|         // Update available languages in list next tick (the event must not be triggered before the listeners) | ||||
|         setTimeout(captions.update.bind(this), 0); | ||||
|     }, | ||||
|     update: function update() { | ||||
|         // Update tracks | ||||
|         var tracks = captions.getTracks.call(this); | ||||
|         this.options.captions = tracks.map(function (_ref) { | ||||
|             var language = _ref.language; | ||||
|             return language; | ||||
|         }); | ||||
|  | ||||
|         // Set language if it hasn't been set already | ||||
|         if (!this.language) { | ||||
|             var language = this.config.captions.language; | ||||
|  | ||||
|             if (language === 'auto') { | ||||
|                 var _split = (navigator.language || navigator.userLanguage).split('-'); | ||||
|  | ||||
|                 var _split2 = slicedToArray(_split, 1); | ||||
|  | ||||
|                 language = _split2[0]; | ||||
|             } | ||||
|             this.language = this.storage.get('language') || (language || '').toLowerCase(); | ||||
|         } | ||||
|  | ||||
|         // Toggle the class hooks | ||||
|         utils.toggleClass(this.elements.container, this.config.classNames.captions.enabled, !utils.is.empty(captions.getTracks.call(this))); | ||||
|  | ||||
|         // Update available languages in list | ||||
|         if ((this.config.controls || []).includes('settings') && this.config.settings.includes('captions')) { | ||||
|             controls.setCaptionsMenu.call(this); | ||||
|         } | ||||
|     }, | ||||
| @ -8914,25 +8892,6 @@ var captions = { | ||||
|         } else { | ||||
|             this.debug.warn('No captions element to render to'); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|  | ||||
|     // Display captions container and button (for initialization) | ||||
|     show: function show() { | ||||
|         // Try to load the value from storage | ||||
|         var active = this.storage.get('captions'); | ||||
|  | ||||
|         // Otherwise fall back to the default config | ||||
|         if (!utils.is.boolean(active)) { | ||||
|             active = this.config.captions.active; | ||||
|         } else { | ||||
|             this.captions.active = active; | ||||
|         } | ||||
|  | ||||
|         if (active) { | ||||
|             utils.toggleClass(this.elements.container, this.config.classNames.captions.active, true); | ||||
|             utils.toggleState(this.elements.buttons.captions, true); | ||||
|         } | ||||
|     } | ||||
| }; | ||||
|  | ||||
| @ -9073,7 +9032,10 @@ var defaults$1 = { | ||||
|     // Captions settings | ||||
|     captions: { | ||||
|         active: false, | ||||
|         language: (navigator.language || navigator.userLanguage).split('-')[0] | ||||
|         language: 'auto', | ||||
|         // Listen to new tracks added after Plyr is initialized. | ||||
|         // This is needed for streaming captions, but may result in unselectable options | ||||
|         update: false | ||||
|     }, | ||||
|  | ||||
|     // Fullscreen settings | ||||
| @ -9130,7 +9092,15 @@ var defaults$1 = { | ||||
|         reset: 'Reset', | ||||
|         disabled: 'Disabled', | ||||
|         enabled: 'Enabled', | ||||
|         advertisement: 'Ad' | ||||
|         advertisement: 'Ad', | ||||
|         qualityBadge: { | ||||
|             2160: '4K', | ||||
|             1440: 'HD', | ||||
|             1080: 'HD', | ||||
|             720: 'HD', | ||||
|             576: 'SD', | ||||
|             480: 'SD' | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     // URLs | ||||
| @ -9589,8 +9559,10 @@ var ui = { | ||||
|         // Remove native controls | ||||
|         ui.toggleNativeControls.call(this); | ||||
|  | ||||
|         // Captions | ||||
|         captions.setup.call(this); | ||||
|         // Setup captions for HTML5 | ||||
|         if (this.isHTML5) { | ||||
|             captions.setup.call(this); | ||||
|         } | ||||
|  | ||||
|         // Reset volume | ||||
|         this.volume = null; | ||||
| @ -9643,6 +9615,12 @@ var ui = { | ||||
|         if (this.poster && this.elements.poster && !this.elements.poster.style.backgroundImage) { | ||||
|             ui.setPoster.call(this, this.poster); | ||||
|         } | ||||
|  | ||||
|         // Manually set the duration if user has overridden it. | ||||
|         // The event listeners for it doesn't get called if preload is disabled (#701) | ||||
|         if (this.config.duration) { | ||||
|             controls.durationUpdate.call(this); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|  | ||||
| @ -12700,24 +12678,19 @@ var Plyr = function () { | ||||
|             } | ||||
|  | ||||
|             // If the method is called without parameter, toggle based on current value | ||||
|             var show = utils.is.boolean(input) ? input : !this.elements.container.classList.contains(this.config.classNames.captions.active); | ||||
|  | ||||
|             // Nothing to change... | ||||
|             if (this.captions.active === show) { | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             // Set global | ||||
|             this.captions.active = show; | ||||
|             var active = utils.is.boolean(input) ? input : !this.elements.container.classList.contains(this.config.classNames.captions.active); | ||||
|  | ||||
|             // Toggle state | ||||
|             utils.toggleState(this.elements.buttons.captions, this.captions.active); | ||||
|             utils.toggleState(this.elements.buttons.captions, active); | ||||
|  | ||||
|             // Add class hook | ||||
|             utils.toggleClass(this.elements.container, this.config.classNames.captions.active, this.captions.active); | ||||
|             utils.toggleClass(this.elements.container, this.config.classNames.captions.active, active); | ||||
|  | ||||
|             // Trigger an event | ||||
|             utils.dispatchEvent.call(this, this.media, this.captions.active ? 'captionsenabled' : 'captionsdisabled'); | ||||
|             // Update state and trigger event | ||||
|             if (active !== this.captions.active) { | ||||
|                 this.captions.active = active; | ||||
|                 utils.dispatchEvent.call(this, this.media, this.captions.active ? 'captionsenabled' : 'captionsdisabled'); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         /** | ||||
| @ -13249,7 +13222,7 @@ var Plyr = function () { | ||||
|                 quality = Number(input); | ||||
|             } | ||||
|  | ||||
|             if (!utils.is.number(quality) || quality === 0) { | ||||
|             if (!utils.is.number(quality)) { | ||||
|                 quality = this.storage.get('quality'); | ||||
|             } | ||||
|  | ||||
|  | ||||
							
								
								
									
										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
											
										
									
								
							| @ -226,9 +226,14 @@ gulp.task('watch', () => { | ||||
|     gulp.watch(paths.demo.src.sass, tasks.sass); | ||||
| }); | ||||
|  | ||||
| // Build distribution | ||||
| gulp.task('build', () => { | ||||
|     run(tasks.clean, tasks.js, tasks.sass, tasks.sprite); | ||||
| }); | ||||
|  | ||||
| // Default gulp task | ||||
| gulp.task('default', () => { | ||||
|     run(tasks.clean, tasks.js, tasks.sass, tasks.sprite, 'watch'); | ||||
|     run('build', 'watch'); | ||||
| }); | ||||
|  | ||||
| // Publish a version to CDN and demo | ||||
|  | ||||
| @ -65,6 +65,8 @@ | ||||
|         "doc": "readme.md" | ||||
|     }, | ||||
|     "scripts": { | ||||
|         "build": "gulp build", | ||||
|         "lint": "eslint src/js", | ||||
|         "test": "echo \"Error: no test specified\" && exit 1" | ||||
|     }, | ||||
|     "author": "Sam Potts <sam@potts.es>", | ||||
|  | ||||
| @ -303,7 +303,7 @@ Note the single quotes encapsulating the JSON and double quotes on the object ke | ||||
| | `invertTime`         | Boolean                    | `true`                                                                                                                         | Display the current time as a countdown rather than an incremental counter.                                                                                                                                                                                                                                                                                            | | ||||
| | `toggleInvert`       | Boolean                    | `true`                                                                                                                         | Allow users to click to toggle the above.                                                                                                                                                                                                                                                                                                                              | | ||||
| | `listeners`          | Object                     | `null`                                                                                                                         | Allows binding of event listeners to the controls before the default handlers. See the `defaults.js` for available listeners. If your handler prevents default on the event (`event.preventDefault()`), the default handler will not fire.                                                                                                                             | | ||||
| | `captions`           | Object                     | `{ active: false, language: window.navigator.language.split('-')[0] }`                                                         | `active`: Toggles if captions should be active by default. `language`: Sets the default language to load (if available).                                                                                                                                                                                                                                               | | ||||
| | `captions`           | Object                     | `{ active: false, language: 'auto', update: false }`                                                         | `active`: Toggles if captions should be active by default. `language`: Sets the default language to load (if available). 'auto' uses the browser language. `update`: Listen to changes to tracks and update menu. This is needed for some streaming libraries, but can result in unselectable language options).                                                                                                                                                                                                                                               | | ||||
| | `fullscreen`         | Object                     | `{ enabled: true, fallback: true, iosNative: false }`                                                                          | `enabled`: Toggles whether fullscreen should be enabled. `fallback`: Allow fallback to a full-window solution. `iosNative`: whether to use native iOS fullscreen when entering fullscreen (no custom controls)                                                                                                                                                         | | ||||
| | `ratio`              | String                     | `16:9`                                                                                                                         | The aspect ratio you want to use for embedded players.                                                                                                                                                                                                                                                                                                                 | | ||||
| | `storage`            | Object                     | `{ enabled: true, key: 'plyr' }`                                                                                               | `enabled`: Allow use of local storage to store user settings. `key`: The key name to use.                                                                                                                                                                                                                                                                              | | ||||
|  | ||||
| @ -16,28 +16,6 @@ const captions = { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         // Set default language if not set | ||||
|         const stored = this.storage.get('language'); | ||||
|  | ||||
|         if (!utils.is.empty(stored)) { | ||||
|             this.captions.language = stored; | ||||
|         } | ||||
|  | ||||
|         if (utils.is.empty(this.captions.language)) { | ||||
|             this.captions.language = this.config.captions.language.toLowerCase(); | ||||
|         } | ||||
|  | ||||
|         // Set captions enabled state if not set | ||||
|         if (!utils.is.boolean(this.captions.active)) { | ||||
|             const active = this.storage.get('captions'); | ||||
|  | ||||
|             if (utils.is.boolean(active)) { | ||||
|                 this.captions.active = active; | ||||
|             } else { | ||||
|                 this.captions.active = this.config.captions.active; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Only Vimeo and HTML5 video supported at this point | ||||
|         if (!this.isVideo || this.isYouTube || (this.isHTML5 && !support.textTracks)) { | ||||
|             // Clear menu and hide | ||||
| @ -55,17 +33,6 @@ const captions = { | ||||
|             utils.insertAfter(this.elements.captions, this.elements.wrapper); | ||||
|         } | ||||
|  | ||||
|         // Set the class hook | ||||
|         utils.toggleClass(this.elements.container, this.config.classNames.captions.enabled, !utils.is.empty(captions.getTracks.call(this))); | ||||
|  | ||||
|         // Get tracks | ||||
|         const tracks = captions.getTracks.call(this); | ||||
|  | ||||
|         // If no caption file exists, hide container for caption text | ||||
|         if (utils.is.empty(tracks)) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         // Get browser info | ||||
|         const browser = utils.getBrowser(); | ||||
|  | ||||
| @ -94,14 +61,45 @@ const captions = { | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         // Set language | ||||
|         captions.setLanguage.call(this); | ||||
|         // Try to load the value from storage | ||||
|         let active = this.storage.get('captions'); | ||||
|  | ||||
|         // Enable UI | ||||
|         captions.show.call(this); | ||||
|         // Otherwise fall back to the default config | ||||
|         if (!utils.is.boolean(active)) { | ||||
|             ({ active } = this.config.captions); | ||||
|         } | ||||
|  | ||||
|         // Set available languages in list | ||||
|         if (utils.is.array(this.config.controls) && this.config.controls.includes('settings') && this.config.settings.includes('captions')) { | ||||
|         // Set toggled state | ||||
|         this.toggleCaptions(active); | ||||
|  | ||||
|         // Watch changes to textTracks and update captions menu | ||||
|         if (this.config.captions.update) { | ||||
|             utils.on(this.media.textTracks, 'addtrack removetrack', captions.update.bind(this)); | ||||
|         } | ||||
|  | ||||
|         // Update available languages in list next tick (the event must not be triggered before the listeners) | ||||
|         setTimeout(captions.update.bind(this), 0); | ||||
|     }, | ||||
|  | ||||
|     update() { | ||||
|         // Update tracks | ||||
|         const tracks = captions.getTracks.call(this); | ||||
|         this.options.captions = tracks.map(({language}) => language); | ||||
|  | ||||
|         // Set language if it hasn't been set already | ||||
|         if (!this.language) { | ||||
|             let { language } = this.config.captions; | ||||
|             if (language === 'auto') { | ||||
|                 [ language ] = (navigator.language || navigator.userLanguage).split('-'); | ||||
|             } | ||||
|             this.language = this.storage.get('language') || (language || '').toLowerCase(); | ||||
|         } | ||||
|  | ||||
|         // Toggle the class hooks | ||||
|         utils.toggleClass(this.elements.container, this.config.classNames.captions.enabled, !utils.is.empty(captions.getTracks.call(this))); | ||||
|  | ||||
|         // Update available languages in list | ||||
|         if ((this.config.controls || []).includes('settings') && this.config.settings.includes('captions')) { | ||||
|             controls.setCaptionsMenu.call(this); | ||||
|         } | ||||
|     }, | ||||
| @ -247,24 +245,6 @@ const captions = { | ||||
|             this.debug.warn('No captions element to render to'); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     // Display captions container and button (for initialization) | ||||
|     show() { | ||||
|         // Try to load the value from storage | ||||
|         let active = this.storage.get('captions'); | ||||
|  | ||||
|         // Otherwise fall back to the default config | ||||
|         if (!utils.is.boolean(active)) { | ||||
|             ({ active } = this.config.captions); | ||||
|         } else { | ||||
|             this.captions.active = active; | ||||
|         } | ||||
|  | ||||
|         if (active) { | ||||
|             utils.toggleClass(this.elements.container, this.config.classNames.captions.active, true); | ||||
|             utils.toggleState(this.elements.buttons.captions, true); | ||||
|         } | ||||
|     }, | ||||
| }; | ||||
|  | ||||
| export default captions; | ||||
|  | ||||
							
								
								
									
										36
									
								
								src/js/controls.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										36
									
								
								src/js/controls.js
									
									
									
									
										vendored
									
									
								
							| @ -664,27 +664,7 @@ const controls = { | ||||
|  | ||||
|         // Get the badge HTML for HD, 4K etc | ||||
|         const getBadge = quality => { | ||||
|             let label = ''; | ||||
|  | ||||
|             switch (quality) { | ||||
|                 case 2160: | ||||
|                     label = '4K'; | ||||
|                     break; | ||||
|  | ||||
|                 case 1440: | ||||
|                 case 1080: | ||||
|                 case 720: | ||||
|                     label = 'HD'; | ||||
|                     break; | ||||
|  | ||||
|                 case 576: | ||||
|                 case 480: | ||||
|                     label = 'SD'; | ||||
|                     break; | ||||
|  | ||||
|                 default: | ||||
|                     break; | ||||
|             } | ||||
|             const label = i18n.get(`qualityBadge.${quality}`, this.config); | ||||
|  | ||||
|             if (!label.length) { | ||||
|                 return null; | ||||
| @ -708,7 +688,6 @@ const controls = { | ||||
|     }, | ||||
|  | ||||
|     // Translate a value into a nice label | ||||
|     // TODO: Localisation | ||||
|     getLabel(setting, value) { | ||||
|         switch (setting) { | ||||
|             case 'speed': | ||||
| @ -716,7 +695,13 @@ const controls = { | ||||
|  | ||||
|             case 'quality': | ||||
|                 if (utils.is.number(value)) { | ||||
|                     return `${value}p`; | ||||
|                     const label = i18n.get(`qualityLabel.${value}`, this.config); | ||||
|  | ||||
|                     if (!label.length) { | ||||
|                         return `${value}p`; | ||||
|                     } | ||||
|  | ||||
|                     return label; | ||||
|                 } | ||||
|  | ||||
|                 return utils.toTitleCase(value); | ||||
| @ -883,13 +868,10 @@ const controls = { | ||||
|                 'language', | ||||
|                 track.label, | ||||
|                 track.language !== 'enabled' ? controls.createBadge.call(this, track.language.toUpperCase()) : null, | ||||
|                 track.language.toLowerCase() === this.captions.language.toLowerCase(), | ||||
|                 track.language.toLowerCase() === this.language, | ||||
|             ); | ||||
|         }); | ||||
|  | ||||
|         // Store reference | ||||
|         this.options.captions = tracks.map(track => track.language); | ||||
|  | ||||
|         controls.updateSetting.call(this, type, list); | ||||
|     }, | ||||
|  | ||||
|  | ||||
| @ -115,7 +115,10 @@ const defaults = { | ||||
|     // Captions settings | ||||
|     captions: { | ||||
|         active: false, | ||||
|         language: (navigator.language || navigator.userLanguage).split('-')[0], | ||||
|         language: 'auto', | ||||
|         // Listen to new tracks added after Plyr is initialized. | ||||
|         // This is needed for streaming captions, but may result in unselectable options | ||||
|         update: false, | ||||
|     }, | ||||
|  | ||||
|     // Fullscreen settings | ||||
| @ -187,6 +190,14 @@ const defaults = { | ||||
|         disabled: 'Disabled', | ||||
|         enabled: 'Enabled', | ||||
|         advertisement: 'Ad', | ||||
|         qualityBadge: { | ||||
|             2160: '4K', | ||||
|             1440: 'HD', | ||||
|             1080: 'HD', | ||||
|             720: 'HD', | ||||
|             576: 'SD', | ||||
|             480: 'SD', | ||||
|         }, | ||||
|     }, | ||||
|  | ||||
|     // URLs | ||||
| @ -311,9 +322,8 @@ const defaults = { | ||||
|         display: { | ||||
|             currentTime: '.plyr__time--current', | ||||
|             duration: '.plyr__time--duration', | ||||
|             buffer: '.plyr__progress--buffer', | ||||
|             played: '.plyr__progress--played', | ||||
|             loop: '.plyr__progress--loop', | ||||
|             buffer: '.plyr__progress__buffer', | ||||
|             loop: '.plyr__progress__loop', // Used later | ||||
|             volume: '.plyr__volume--display', | ||||
|         }, | ||||
|         progress: '.plyr__progress', | ||||
|  | ||||
| @ -99,6 +99,13 @@ const html5 = { | ||||
|                 // Set new source | ||||
|                 player.media.src = supported[0].getAttribute('src'); | ||||
|  | ||||
|                 // Restore time | ||||
|                 const onLoadedMetaData = () => { | ||||
|                     player.currentTime = currentTime; | ||||
|                     player.off('loadedmetadata', onLoadedMetaData); | ||||
|                 }; | ||||
|                 player.on('loadedmetadata', onLoadedMetaData); | ||||
|  | ||||
|                 // Load new source | ||||
|                 player.media.load(); | ||||
|  | ||||
| @ -107,9 +114,6 @@ const html5 = { | ||||
|                     player.play(); | ||||
|                 } | ||||
|  | ||||
|                 // Restore time | ||||
|                 player.currentTime = currentTime; | ||||
|  | ||||
|                 // Trigger change event | ||||
|                 utils.dispatchEvent.call(player, player.media, 'qualitychange', false, { | ||||
|                     quality: input, | ||||
|  | ||||
| @ -6,11 +6,15 @@ import utils from './utils'; | ||||
|  | ||||
| const i18n = { | ||||
|     get(key = '', config = {}) { | ||||
|         if (utils.is.empty(key) || utils.is.empty(config) || !Object.keys(config.i18n).includes(key)) { | ||||
|         if (utils.is.empty(key) || utils.is.empty(config)) { | ||||
|             return ''; | ||||
|         } | ||||
|  | ||||
|         let string = config.i18n[key]; | ||||
|         let string = utils.getDeep(config.i18n, key); | ||||
|  | ||||
|         if (utils.is.empty(string)) { | ||||
|             return ''; | ||||
|         } | ||||
|  | ||||
|         const replace = { | ||||
|             '{seektime}': config.seekTime, | ||||
|  | ||||
| @ -675,7 +675,7 @@ class Plyr { | ||||
|             quality = Number(input); | ||||
|         } | ||||
|  | ||||
|         if (!utils.is.number(quality) || quality === 0) { | ||||
|         if (!utils.is.number(quality)) { | ||||
|             quality = this.storage.get('quality'); | ||||
|         } | ||||
|  | ||||
| @ -838,24 +838,19 @@ class Plyr { | ||||
|         } | ||||
|  | ||||
|         // If the method is called without parameter, toggle based on current value | ||||
|         const show = utils.is.boolean(input) ? input : !this.elements.container.classList.contains(this.config.classNames.captions.active); | ||||
|  | ||||
|         // Nothing to change... | ||||
|         if (this.captions.active === show) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         // Set global | ||||
|         this.captions.active = show; | ||||
|         const active = utils.is.boolean(input) ? input : !this.elements.container.classList.contains(this.config.classNames.captions.active); | ||||
|  | ||||
|         // Toggle state | ||||
|         utils.toggleState(this.elements.buttons.captions, this.captions.active); | ||||
|         utils.toggleState(this.elements.buttons.captions, active); | ||||
|  | ||||
|         // Add class hook | ||||
|         utils.toggleClass(this.elements.container, this.config.classNames.captions.active, this.captions.active); | ||||
|         utils.toggleClass(this.elements.container, this.config.classNames.captions.active, active); | ||||
|  | ||||
|         // Trigger an event | ||||
|         utils.dispatchEvent.call(this, this.media, this.captions.active ? 'captionsenabled' : 'captionsdisabled'); | ||||
|         // Update state and trigger event | ||||
|         if (active !== this.captions.active) { | ||||
|             this.captions.active = active; | ||||
|             utils.dispatchEvent.call(this, this.media, this.captions.active ? 'captionsenabled' : 'captionsdisabled'); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|  | ||||
							
								
								
									
										12
									
								
								src/js/ui.js
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								src/js/ui.js
									
									
									
									
									
								
							| @ -55,8 +55,10 @@ const ui = { | ||||
|         // Remove native controls | ||||
|         ui.toggleNativeControls.call(this); | ||||
|  | ||||
|         // Captions | ||||
|         captions.setup.call(this); | ||||
|         // Setup captions for HTML5 | ||||
|         if (this.isHTML5) { | ||||
|             captions.setup.call(this); | ||||
|         } | ||||
|  | ||||
|         // Reset volume | ||||
|         this.volume = null; | ||||
| @ -109,6 +111,12 @@ const ui = { | ||||
|         if (this.poster && this.elements.poster && !this.elements.poster.style.backgroundImage) { | ||||
|             ui.setPoster.call(this, this.poster); | ||||
|         } | ||||
|  | ||||
|         // Manually set the duration if user has overridden it. | ||||
|         // The event listeners for it doesn't get called if preload is disabled (#701) | ||||
|         if (this.config.duration) { | ||||
|             controls.durationUpdate.call(this); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     // Setup aria attribute for play and iframe title | ||||
|  | ||||
| @ -728,6 +728,11 @@ const utils = { | ||||
|         return JSON.parse(JSON.stringify(object)); | ||||
|     }, | ||||
|  | ||||
|     // Get a nested value in an object | ||||
|     getDeep(object, path) { | ||||
|         return path.split('.').reduce((obj, key) => obj && obj[key], object); | ||||
|     }, | ||||
|  | ||||
|     // Get the closest value in an array | ||||
|     closest(array, value) { | ||||
|         if (!utils.is.array(array) || !array.length) { | ||||
|  | ||||
| @ -5,16 +5,21 @@ | ||||
| .plyr__progress { | ||||
|     display: flex; | ||||
|     flex: 1; | ||||
|     position: relative; | ||||
|     margin-right: $plyr-range-thumb-height; | ||||
|     left: $plyr-range-thumb-height / 2; | ||||
|     margin-right: $plyr-range-thumb-height; | ||||
|     position: relative; | ||||
|  | ||||
|     input[type='range'], | ||||
|     &__buffer { | ||||
|         margin-left: -($plyr-range-thumb-height / 2); | ||||
|         margin-right: -($plyr-range-thumb-height / 2); | ||||
|         // Offset the range thumb in order to be able to calculate the relative progress (#954) | ||||
|         width: calc(100% + #{$plyr-range-thumb-height}); | ||||
|     } | ||||
|  | ||||
|     input[type='range'] { | ||||
|         position: relative; | ||||
|         z-index: 2; | ||||
|         // Offset the range thumb in order to be able to calculate the relative progress (#954) | ||||
|         width: calc(100% + #{$plyr-range-thumb-height}) !important; | ||||
|         margin: 0 -#{$plyr-range-thumb-height / 2} !important; | ||||
|     } | ||||
|  | ||||
|     // Seek tooltip to show time | ||||
| @ -24,18 +29,17 @@ | ||||
|     } | ||||
| } | ||||
|  | ||||
| .plyr__progress--buffer { | ||||
| .plyr__progress__buffer { | ||||
|     -webkit-appearance: none; /* stylelint-disable-line */ | ||||
|     background: transparent; | ||||
|     border: 0; | ||||
|     border-radius: 100px; | ||||
|     height: $plyr-range-track-height; | ||||
|     left: 0; | ||||
|     margin: -($plyr-range-track-height / 2) 0 0; | ||||
|     margin-top: -($plyr-range-track-height / 2); | ||||
|     padding: 0; | ||||
|     position: absolute; | ||||
|     top: 50%; | ||||
|     width: 100%; | ||||
|  | ||||
|     &::-webkit-progress-bar { | ||||
|         background: transparent; | ||||
| @ -63,17 +67,17 @@ | ||||
|     } | ||||
| } | ||||
|  | ||||
| .plyr--video .plyr__progress--buffer { | ||||
| .plyr--video .plyr__progress__buffer { | ||||
|     box-shadow: 0 1px 1px rgba(#000, 0.15); | ||||
|     color: $plyr-video-progress-buffered-bg; | ||||
| } | ||||
|  | ||||
| .plyr--audio .plyr__progress--buffer { | ||||
| .plyr--audio .plyr__progress__buffer { | ||||
|     color: $plyr-audio-progress-buffered-bg; | ||||
| } | ||||
|  | ||||
| // Loading state | ||||
| .plyr--loading .plyr__progress--buffer { | ||||
| .plyr--loading .plyr__progress__buffer { | ||||
|     animation: plyr-progress 1s linear infinite; | ||||
|     background-image: linear-gradient( | ||||
|         -45deg, | ||||
| @ -90,10 +94,10 @@ | ||||
|     color: transparent; | ||||
| } | ||||
|  | ||||
| .plyr--video.plyr--loading .plyr__progress--buffer { | ||||
| .plyr--video.plyr--loading .plyr__progress__buffer { | ||||
|     background-color: $plyr-video-progress-buffered-bg; | ||||
| } | ||||
|  | ||||
| .plyr--audio.plyr--loading .plyr__progress--buffer { | ||||
| .plyr--audio.plyr--loading .plyr__progress__buffer { | ||||
|     background-color: $plyr-audio-progress-buffered-bg; | ||||
| } | ||||
|  | ||||
| @ -31,12 +31,12 @@ | ||||
| @import 'components/controls'; | ||||
| @import 'components/embed'; | ||||
| @import 'components/menus'; | ||||
| @import 'components/progress'; | ||||
| @import 'components/poster'; | ||||
| @import 'components/sliders'; | ||||
| @import 'components/poster'; | ||||
| @import 'components/times'; | ||||
| @import 'components/tooltips'; | ||||
| @import 'components/video'; | ||||
| @import 'components/progress'; | ||||
| @import 'components/volume'; | ||||
|  | ||||
| @import 'states/fullscreen'; | ||||
|  | ||||
		Reference in New Issue
	
	Block a user