<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>JSDoc: Source: plugin.js</title>

    <script src="scripts/prettify/prettify.js"> </script>
    <script src="scripts/prettify/lang-css.js"> </script>
    <!--[if lt IE 9]>
      <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
    <![endif]-->
    <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
    <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>

<body>

<div id="main">

    <h1 class="page-title">Source: plugin.js</h1>

    



    
    <section>
        <article>
            <pre class="prettyprint source linenums"><code>import videojs from 'video.js'
import { version as VERSION } from '../package.json'
// import request from 'request';

// Default options for the plugin.
const defaults = {}

// Cross-compatibility for Video.js 5 and 6.
const registerPlugin = videojs.registerPlugin || videojs.plugin
// const dom = videojs.dom || videojs;

/**
 * Function to invoke when the player is ready.
 *
 * This is a great place for your plugin to initialize itself. When this
 * function is called, the player will have its DOM and child components
 * in place.
 *
 * @function onPlayerReady
 * @param    {Player} player
 *           A Video.js player object.
 *
 * @param    {Object} [options={}]
 *           A plain object containing options for the plugin.
 */
const onPlayerReady = (player, options) => {
  player.addClass('vjs-vtt-thumbnails')
  new vttThumbnailsPlugin(player, options)
}

/**
 * A video.js plugin.
 *
 * In the plugin function, the value of `this` is a video.js `Player`
 * instance. You cannot rely on the player being in a "ready" state here,
 * depending on how the plugin is invoked. This may or may not be important
 * to you; if not, remove the wait for "ready"!
 *
 * @function vttThumbnails
 * @param    {Object} [options={}]
 *           An object of options left to the plugin author to define.
 */
const vttThumbnails = function (options) {
  this.ready(() => {
    onPlayerReady(this, videojs.mergeOptions(defaults, options))
  })
}

/**
 * VTT Thumbnails class.
 *
 * This class performs all functions related to displaying the vtt
 * thumbnails.
 */
class vttThumbnailsPlugin {

  /**
   * Plugin class constructor, called by videojs on
   * ready event.
   *
   * @function  constructor
   * @param    {Player} player
   *           A Video.js player object.
   *
   * @param    {Object} [options={}]
   *           A plain object containing options for the plugin.
   */
  constructor (player, options) {
    this.player = player
    this.options = options
    this.initializeThumbnails()
  }

  /**
   * Bootstrap the plugin.
   */
  initializeThumbnails () {
    if (!this.options.src) {
      return
    }
    const baseUrl = this.getBaseUrl();
    const url = this.getFullyQualifiedUrl(this.options.src, baseUrl);
    this.getVttFile(url)
      .then((data) => {
        this.vttData = this.processVtt(data)
        this.setupThumbnailElement()
      });
  }

  /**
   * Builds a base URL should we require one.
   *
   * @returns {string}
   */
  getBaseUrl () {
    return [
      window.location.protocol,
      '//',
      window.location.hostname,
      (window.location.port ? ':' + window.location.port : ''),
      window.location.pathname
    ].join('').split(/([^\/]*)$/gi).shift()
  }

  /**
   * Grabs the contents of the VTT file.
   *
   * @param url
   * @returns {Promise}
   */
  getVttFile (url) {
    return new Promise((resolve, reject) => {
      const req = new XMLHttpRequest()
      req.data = {
        resolve: resolve
      };
      req.addEventListener('load', this.vttFileLoaded);
      req.open('GET', url)
      req.send()
    })
  }

  /**
   * Callback for loaded VTT file.
   */
  vttFileLoaded () {
    this.data.resolve(this.responseText)
  }

  setupThumbnailElement (data) {
    const mouseDisplay = this.player.$('.vjs-mouse-display')
    this.progressBar = this.player.$('.vjs-progress-control')
    const thumbHolder = document.createElement('div')
    thumbHolder.setAttribute('class', 'vjs-vtt-thumbnail-display')
    this.progressBar.appendChild(thumbHolder)
    this.thumbnailHolder = thumbHolder
    mouseDisplay.classList.add('vjs-hidden')
    this.progressBar.addEventListener('mouseenter', () => { return this.onBarMouseenter() })
    this.progressBar.addEventListener('mouseleave', () => { return this.onBarMouseleave() })
  }

  onBarMouseenter () {
    this.mouseMoveCallback = (e) => { this.onBarMousemove(e) }
    this.progressBar.addEventListener('mousemove', this.mouseMoveCallback)
    this.showThumbnailHolder()
  }

  onBarMouseleave () {
    this.progressBar.removeEventListener('mousemove', this.mouseMoveCallback)
    this.hideThumbnailHolder()
  }

  onBarMousemove (event) {
    this.updateThumbnailStyle(
      event.clientX - this.progressBar.offsetLeft,
      this.progressBar.offsetWidth
    )
  }

  getStyleForTime (time) {
    for (let i = 0; i &lt; this.vttData.length; ++i) {
      let item = this.vttData[i]
      if (time >= item.start &amp;&amp; time &lt; item.end) {
        return item.css
      }
    }
  }

  showThumbnailHolder () {
    this.thumbnailHolder.style.opacity = '1'
  }

  hideThumbnailHolder () {
    this.thumbnailHolder.style.opacity = '0'
  }

  updateThumbnailStyle (x, width) {
    const duration = this.player.duration()
    const time = ((1 - ((width - x) / width))) * duration
    const currentStyle = this.getStyleForTime(time)
    if (!currentStyle) {
      return this.hideThumbnailHolder()
    }
    const xPos = ((1 - ((width - x) / width))) * width
    this.thumbnailHolder.style.transform = 'translateX(' + xPos + 'px)'
    this.thumbnailHolder.style.marginLeft = '-' + (parseInt(currentStyle.width) / 2) + 'px'

    if (this.lastStyle &amp;&amp; this.lastStyle === currentStyle) {
      return
    }
    this.lastStyle = currentStyle

    for (let style in currentStyle) {
      if (currentStyle.hasOwnProperty(style)) {
        this.thumbnailHolder.style[style] = currentStyle[style]
      }
    }
  }

  processVtt (data) {
    const processedVtts = []
    const vttDefinitions = data.split(/[\r\n][\r\n]/i)
    vttDefinitions.forEach((vttDef) => {
      if (vttDef.match(/([0-9]{2}:)?([0-9]{2}:)?[0-9]{2}(.[0-9]{3})?( ?--> ?)([0-9]{2}:)?([0-9]{2}:)?[0-9]{2}(.[0-9]{3})?[\r\n]{1}.*/gi)) {
        let vttDefSplit = vttDef.split(/[\r\n]/i)
        let vttTiming = vttDefSplit[0]
        let vttTimingSplit = vttTiming.split(/ ?--> ?/i)
        let vttTimeStart = vttTimingSplit[0]
        let vttTimeEnd = vttTimingSplit[1]
        let vttImageDef = vttDefSplit[1]
        let vttCssDef = this.getVttCss(vttImageDef)

        processedVtts.push({
          start: this.getSecondsFromTimestamp(vttTimeStart),
          end: this.getSecondsFromTimestamp(vttTimeEnd),
          css: vttCssDef
        })

      }
    })
    return processedVtts
  }

  getFullyQualifiedUrl (path, base) {
    if (!path.match(/\/\//i)) {
      return [
        this.trim(base, '/'),
        this.trim(path, '/')
      ].join('/')
    }
    return path
  }

  getPropsFromDef (def) {
    const imageDefSplit = def.split(/#xywh=/i)
    const imageUrl = imageDefSplit[0]
    const imageCoords = imageDefSplit[1]
    const splitCoords = imageCoords.match(/[0-9]+/gi)
    return {
      x: splitCoords[0],
      y: splitCoords[1],
      w: splitCoords[2],
      h: splitCoords[3],
      image: imageUrl
    }
  }

  getVttCss (vttImageDef) {

    const cssObj = {}

    // If there isn't a protocol, use the VTT source URL.
    const baseSplit = this.options.src.split(/([^\/]*)$/gi)
    vttImageDef = this.getFullyQualifiedUrl(vttImageDef, baseSplit[0])

    if (!vttImageDef.match(/#xywh=/i)) {
      cssObj.background = 'url("' + vttImageDef + '")'
      return cssObj
    }

    const imageProps = this.getPropsFromDef(vttImageDef)
    cssObj.background = 'url("' + imageProps.image + '") no-repeat -' + imageProps.x + 'px -' + imageProps.y + 'px'
    cssObj.width = imageProps.w + 'px'
    cssObj.height = imageProps.h + 'px'

    return cssObj
  }

  doconstructTimestamp (timestamp) {
    const splitStampMilliseconds = timestamp.split('.')
    const timeParts = splitStampMilliseconds[0]
    const timePartsSplit = timeParts.split(':')
    return {
      milliseconds: parseInt(splitStampMilliseconds[1]) || 0,
      seconds: parseInt(timePartsSplit.pop()) || 0,
      minutes: parseInt(timePartsSplit.pop()) || 0,
      hours: parseInt(timePartsSplit.pop()) || 0,
    }

  }

  getSecondsFromTimestamp (timestamp) {
    const timestampParts = this.doconstructTimestamp(timestamp)
    return parseInt((timestampParts.hours * (60 * 60)) +
      (timestampParts.minutes * 60) +
      timestampParts.seconds +
      (timestampParts.milliseconds * 1000))
  }

  trim (str, charlist) {
    let whitespace = [
      ' ',
      '\n',
      '\r',
      '\t',
      '\f',
      '\x0b',
      '\xa0',
      '\u2000',
      '\u2001',
      '\u2002',
      '\u2003',
      '\u2004',
      '\u2005',
      '\u2006',
      '\u2007',
      '\u2008',
      '\u2009',
      '\u200a',
      '\u200b',
      '\u2028',
      '\u2029',
      '\u3000'
    ].join('')
    let l = 0
    let i = 0
    str += ''
    if (charlist) {
      whitespace = (charlist + '').replace(/([[\]().?/*{}+$^:])/g, '$1')
    }
    l = str.length
    for (i = 0; i &lt; l; i++) {
      if (whitespace.indexOf(str.charAt(i)) === -1) {
        str = str.substring(i)
        break
      }
    }
    l = str.length
    for (i = l - 1; i >= 0; i--) {
      if (whitespace.indexOf(str.charAt(i)) === -1) {
        str = str.substring(0, i + 1)
        break
      }
    }
    return whitespace.indexOf(str.charAt(0)) === -1 ? str : ''
  }

}

// Register the plugin with video.js.
registerPlugin('vttThumbnails', vttThumbnails)

// Include the version number.
vttThumbnails.VERSION = VERSION

export default vttThumbnails
</code></pre>
        </article>
    </section>




</div>

<nav>
    <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="vttThumbnailsPlugin.html">vttThumbnailsPlugin</a></li></ul><h3>Global</h3><ul><li><a href="global.html#constructor">constructor</a></li><li><a href="global.html#onPlayerReady">onPlayerReady</a></li><li><a href="global.html#vttThumbnails">vttThumbnails</a></li></ul>
</nav>

<br class="clear">

<footer>
    Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Fri Nov 10 2017 11:42:55 GMT-0500 (EST)
</footer>

<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>