diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/js/captions.js | 94 | ||||
| -rw-r--r-- | src/js/controls.js | 36 | ||||
| -rw-r--r-- | src/js/defaults.js | 18 | ||||
| -rw-r--r-- | src/js/html5.js | 10 | ||||
| -rw-r--r-- | src/js/i18n.js | 8 | ||||
| -rw-r--r-- | src/js/plyr.js | 23 | ||||
| -rw-r--r-- | src/js/ui.js | 12 | ||||
| -rw-r--r-- | src/js/utils.js | 5 | ||||
| -rw-r--r-- | src/sass/components/progress.scss | 30 | ||||
| -rw-r--r-- | src/sass/plyr.scss | 4 | 
10 files changed, 116 insertions, 124 deletions
| diff --git a/src/js/captions.js b/src/js/captions.js index df717351..30c4bc74 100644 --- a/src/js/captions.js +++ b/src/js/captions.js @@ -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'); + +        // Otherwise fall back to the default config +        if (!utils.is.boolean(active)) { +            ({ active } = this.config.captions); +        } -        // Enable UI -        captions.show.call(this); +        // Set toggled state +        this.toggleCaptions(active); -        // Set available languages in list -        if (utils.is.array(this.config.controls) && this.config.controls.includes('settings') && this.config.settings.includes('captions')) { +        // 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; diff --git a/src/js/controls.js b/src/js/controls.js index c76bd66b..20518f9c 100644 --- a/src/js/controls.js +++ b/src/js/controls.js @@ -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);      }, diff --git a/src/js/defaults.js b/src/js/defaults.js index 34e077ee..16df8624 100644 --- a/src/js/defaults.js +++ b/src/js/defaults.js @@ -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', diff --git a/src/js/html5.js b/src/js/html5.js index 3818a441..63596cfc 100644 --- a/src/js/html5.js +++ b/src/js/html5.js @@ -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, diff --git a/src/js/i18n.js b/src/js/i18n.js index 58c3e7cf..62e5bdb0 100644 --- a/src/js/i18n.js +++ b/src/js/i18n.js @@ -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, diff --git a/src/js/plyr.js b/src/js/plyr.js index dcc9fee6..5c51d617 100644 --- a/src/js/plyr.js +++ b/src/js/plyr.js @@ -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'); +        }      }      /** diff --git a/src/js/ui.js b/src/js/ui.js index 3a8f2d05..d6ab0e59 100644 --- a/src/js/ui.js +++ b/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 diff --git a/src/js/utils.js b/src/js/utils.js index 0334879d..b6ba0941 100644 --- a/src/js/utils.js +++ b/src/js/utils.js @@ -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) { diff --git a/src/sass/components/progress.scss b/src/sass/components/progress.scss index 60994f99..eddd32ab 100644 --- a/src/sass/components/progress.scss +++ b/src/sass/components/progress.scss @@ -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;  } diff --git a/src/sass/plyr.scss b/src/sass/plyr.scss index e934cf92..3d824f7d 100644 --- a/src/sass/plyr.scss +++ b/src/sass/plyr.scss @@ -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'; | 
