harella1/video.js

View on GitHub
src/js/tracks/text-track-settings.js

Summary

Maintainability
C
1 day
Test Coverage
/**
 * @file text-track-settings.js
 */
import Component from '../component';
import * as Events from '../utils/events.js';
import * as Fn from '../utils/fn.js';
import log from '../utils/log.js';
import safeParseTuple from 'safe-json-parse/tuple';
import window from 'global/window';

/**
 * Manipulate settings of texttracks
 *
 * @param {Object} player  Main Player
 * @param {Object=} options Object of option names and values
 * @extends Component
 * @class TextTrackSettings
 */
class TextTrackSettings extends Component {

  constructor(player, options) {
    super(player, options);
    this.hide();

    // Grab `persistTextTrackSettings` from the player options if not passed in child options
    if (options.persistTextTrackSettings === undefined) {
      this.options_.persistTextTrackSettings = this.options_.playerOptions.persistTextTrackSettings;
    }

    Events.on(this.$('.vjs-done-button'), 'click', Fn.bind(this, function() {
      this.saveSettings();
      this.hide();
    }));

    Events.on(this.$('.vjs-default-button'), 'click', Fn.bind(this, function() {
      this.$('.vjs-fg-color > select').selectedIndex = 0;
      this.$('.vjs-bg-color > select').selectedIndex = 0;
      this.$('.window-color > select').selectedIndex = 0;
      this.$('.vjs-text-opacity > select').selectedIndex = 0;
      this.$('.vjs-bg-opacity > select').selectedIndex = 0;
      this.$('.vjs-window-opacity > select').selectedIndex = 0;
      this.$('.vjs-edge-style select').selectedIndex = 0;
      this.$('.vjs-font-family select').selectedIndex = 0;
      this.$('.vjs-font-percent select').selectedIndex = 2;
      this.updateDisplay();
    }));

    Events.on(this.$('.vjs-fg-color > select'), 'change', Fn.bind(this, this.updateDisplay));
    Events.on(this.$('.vjs-bg-color > select'), 'change', Fn.bind(this, this.updateDisplay));
    Events.on(this.$('.window-color > select'), 'change', Fn.bind(this, this.updateDisplay));
    Events.on(this.$('.vjs-text-opacity > select'), 'change', Fn.bind(this, this.updateDisplay));
    Events.on(this.$('.vjs-bg-opacity > select'), 'change', Fn.bind(this, this.updateDisplay));
    Events.on(this.$('.vjs-window-opacity > select'), 'change', Fn.bind(this, this.updateDisplay));
    Events.on(this.$('.vjs-font-percent select'), 'change', Fn.bind(this, this.updateDisplay));
    Events.on(this.$('.vjs-edge-style select'), 'change', Fn.bind(this, this.updateDisplay));
    Events.on(this.$('.vjs-font-family select'), 'change', Fn.bind(this, this.updateDisplay));

    if (this.options_.persistTextTrackSettings) {
      this.restoreSettings();
    }
  }

  /**
   * Create the component's DOM element
   *
   * @return {Element}
   * @method createEl
   */
  createEl() {
    return super.createEl('div', {
      className: 'vjs-caption-settings vjs-modal-overlay',
      innerHTML: captionOptionsMenuTemplate()
    });
  }

  /**
   * Get texttrack settings
   * Settings are
   * .vjs-edge-style
   * .vjs-font-family
   * .vjs-fg-color
   * .vjs-text-opacity
   * .vjs-bg-color
   * .vjs-bg-opacity
   * .window-color
   * .vjs-window-opacity
   *
   * @return {Object}
   * @method getValues
   */
  getValues() {
    const textEdge = getSelectedOptionValue(this.$('.vjs-edge-style select'));
    const fontFamily = getSelectedOptionValue(this.$('.vjs-font-family select'));
    const fgColor = getSelectedOptionValue(this.$('.vjs-fg-color > select'));
    const textOpacity = getSelectedOptionValue(this.$('.vjs-text-opacity > select'));
    const bgColor = getSelectedOptionValue(this.$('.vjs-bg-color > select'));
    const bgOpacity = getSelectedOptionValue(this.$('.vjs-bg-opacity > select'));
    const windowColor = getSelectedOptionValue(this.$('.window-color > select'));
    const windowOpacity = getSelectedOptionValue(this.$('.vjs-window-opacity > select'));
    const fontPercent = window['parseFloat'](getSelectedOptionValue(this.$('.vjs-font-percent > select')));

    let result = {
      'backgroundOpacity': bgOpacity,
      'textOpacity': textOpacity,
      'windowOpacity': windowOpacity,
      'edgeStyle': textEdge,
      'fontFamily': fontFamily,
      'color': fgColor,
      'backgroundColor': bgColor,
      'windowColor': windowColor,
      'fontPercent': fontPercent
    };
    for (let name in result) {
      if (result[name] === '' || result[name] === 'none' || (name === 'fontPercent' && result[name] === 1.00)) {
        delete result[name];
      }
    }
    return result;
  }

  /**
   * Set texttrack settings
   * Settings are
   * .vjs-edge-style
   * .vjs-font-family
   * .vjs-fg-color
   * .vjs-text-opacity
   * .vjs-bg-color
   * .vjs-bg-opacity
   * .window-color
   * .vjs-window-opacity
   *
   * @param {Object} values Object with texttrack setting values
   * @method setValues
   */
  setValues(values) {
    setSelectedOption(this.$('.vjs-edge-style select'), values.edgeStyle);
    setSelectedOption(this.$('.vjs-font-family select'), values.fontFamily);
    setSelectedOption(this.$('.vjs-fg-color > select'), values.color);
    setSelectedOption(this.$('.vjs-text-opacity > select'), values.textOpacity);
    setSelectedOption(this.$('.vjs-bg-color > select'), values.backgroundColor);
    setSelectedOption(this.$('.vjs-bg-opacity > select'), values.backgroundOpacity);
    setSelectedOption(this.$('.window-color > select'), values.windowColor);
    setSelectedOption(this.$('.vjs-window-opacity > select'), values.windowOpacity);

    let fontPercent = values.fontPercent;

    if (fontPercent) {
      fontPercent = fontPercent.toFixed(2);
    }

    setSelectedOption(this.$('.vjs-font-percent > select'), fontPercent);
  }

  /**
   * Restore texttrack settings
   *
   * @method restoreSettings
   */
  restoreSettings() {
    let err, values;

    try {
      [err, values] = safeParseTuple(window.localStorage.getItem('vjs-text-track-settings'));

      if (err) {
        log.error(err);
      }
    } catch (e) {
      log.warn(e);
    }

    if (values) {
      this.setValues(values);
    }
  }

  /**
   * Save texttrack settings to local storage
   *
   * @method saveSettings
   */
  saveSettings() {
    if (!this.options_.persistTextTrackSettings) {
      return;
    }

    let values = this.getValues();
    try {
      if (Object.getOwnPropertyNames(values).length > 0) {
        window.localStorage.setItem('vjs-text-track-settings', JSON.stringify(values));
      } else {
        window.localStorage.removeItem('vjs-text-track-settings');
      }
    } catch (e) {
      log.warn(e);
    }
  }

  /**
   * Update display of texttrack settings
   *
   * @method updateDisplay
   */
  updateDisplay() {
    let ttDisplay = this.player_.getChild('textTrackDisplay');
    if (ttDisplay) {
      ttDisplay.updateDisplay();
    }
  }

}

Component.registerComponent('TextTrackSettings', TextTrackSettings);

function getSelectedOptionValue(target) {
  let selectedOption;
  // not all browsers support selectedOptions, so, fallback to options
  if (target.selectedOptions) {
    selectedOption = target.selectedOptions[0];
  } else if (target.options) {
    selectedOption = target.options[target.options.selectedIndex];
  }

  return selectedOption.value;
}

function setSelectedOption(target, value) {
  if (!value) {
    return;
  }

  let i;
  for (i = 0; i < target.options.length; i++) {
    const option = target.options[i];
    if (option.value === value) {
      break;
    }
  }

  target.selectedIndex = i;
}

function captionOptionsMenuTemplate() {
  let template = `<div class="vjs-tracksettings">
      <div class="vjs-tracksettings-colors">
        <div class="vjs-fg-color vjs-tracksetting">
            <label class="vjs-label">Foreground</label>
            <select>
              <option value="">---</option>
              <option value="#FFF">White</option>
              <option value="#000">Black</option>
              <option value="#F00">Red</option>
              <option value="#0F0">Green</option>
              <option value="#00F">Blue</option>
              <option value="#FF0">Yellow</option>
              <option value="#F0F">Magenta</option>
              <option value="#0FF">Cyan</option>
            </select>
            <span class="vjs-text-opacity vjs-opacity">
              <select>
                <option value="">---</option>
                <option value="1">Opaque</option>
                <option value="0.5">Semi-Opaque</option>
              </select>
            </span>
        </div> <!-- vjs-fg-color -->
        <div class="vjs-bg-color vjs-tracksetting">
            <label class="vjs-label">Background</label>
            <select>
              <option value="">---</option>
              <option value="#FFF">White</option>
              <option value="#000">Black</option>
              <option value="#F00">Red</option>
              <option value="#0F0">Green</option>
              <option value="#00F">Blue</option>
              <option value="#FF0">Yellow</option>
              <option value="#F0F">Magenta</option>
              <option value="#0FF">Cyan</option>
            </select>
            <span class="vjs-bg-opacity vjs-opacity">
                <select>
                  <option value="">---</option>
                  <option value="1">Opaque</option>
                  <option value="0.5">Semi-Transparent</option>
                  <option value="0">Transparent</option>
                </select>
            </span>
        </div> <!-- vjs-bg-color -->
        <div class="window-color vjs-tracksetting">
            <label class="vjs-label">Window</label>
            <select>
              <option value="">---</option>
              <option value="#FFF">White</option>
              <option value="#000">Black</option>
              <option value="#F00">Red</option>
              <option value="#0F0">Green</option>
              <option value="#00F">Blue</option>
              <option value="#FF0">Yellow</option>
              <option value="#F0F">Magenta</option>
              <option value="#0FF">Cyan</option>
            </select>
            <span class="vjs-window-opacity vjs-opacity">
                <select>
                  <option value="">---</option>
                  <option value="1">Opaque</option>
                  <option value="0.5">Semi-Transparent</option>
                  <option value="0">Transparent</option>
                </select>
            </span>
        </div> <!-- vjs-window-color -->
      </div> <!-- vjs-tracksettings -->
      <div class="vjs-tracksettings-font">
        <div class="vjs-font-percent vjs-tracksetting">
          <label class="vjs-label">Font Size</label>
          <select>
            <option value="0.50">50%</option>
            <option value="0.75">75%</option>
            <option value="1.00" selected>100%</option>
            <option value="1.25">125%</option>
            <option value="1.50">150%</option>
            <option value="1.75">175%</option>
            <option value="2.00">200%</option>
            <option value="3.00">300%</option>
            <option value="4.00">400%</option>
          </select>
        </div> <!-- vjs-font-percent -->
        <div class="vjs-edge-style vjs-tracksetting">
          <label class="vjs-label">Text Edge Style</label>
          <select>
            <option value="none">None</option>
            <option value="raised">Raised</option>
            <option value="depressed">Depressed</option>
            <option value="uniform">Uniform</option>
            <option value="dropshadow">Dropshadow</option>
          </select>
        </div> <!-- vjs-edge-style -->
        <div class="vjs-font-family vjs-tracksetting">
          <label class="vjs-label">Font Family</label>
          <select>
            <option value="">Default</option>
            <option value="monospaceSerif">Monospace Serif</option>
            <option value="proportionalSerif">Proportional Serif</option>
            <option value="monospaceSansSerif">Monospace Sans-Serif</option>
            <option value="proportionalSansSerif">Proportional Sans-Serif</option>
            <option value="casual">Casual</option>
            <option value="script">Script</option>
            <option value="small-caps">Small Caps</option>
          </select>
        </div> <!-- vjs-font-family -->
      </div>
    </div>
    <div class="vjs-tracksettings-controls">
      <button class="vjs-default-button">Defaults</button>
      <button class="vjs-done-button">Done</button>
    </div>`;

    return template;
}

export default TextTrackSettings;