← back to Dw Theme Hamburger

assets/element.base-media.js

95 lines

import inView from 'vendor.in-view'

export default class extends HTMLElement {
  constructor() {
    super()
    this.player = null
    this.pausedByUser = false
    this.playingWhenLastViewed = false
  }

  connectedCallback() {
    if (!this.hasAttribute('defer-hydration')) {
      this.hydrate()
    }
  }

  async hydrate() {
    const playerTarget = this.getPlayerTarget()
    const handler = {
      get: (target, prop) => {
        return async () => {
          const resolvedTarget = await target
          this.playerHandler(resolvedTarget, prop)
        }
      }
    }

    this.player = new Proxy(playerTarget, handler)
    this.setupInViewHandler()
  }

  setupInViewHandler() {
    inView(this, () => {
      if ((this.autoplay && !this.pausedByUser) || this.playingWhenLastViewed) {
        this.play()
      }
      return () => {
        this.playingWhenLastViewed = this.playing
        this.pause()
      }
    })
  }

  static get observedAttributes() {
    return ['defer-hydration', 'playing']
  }

  attributeChangedCallback(name, oldValue, newValue) {
    if (name === 'defer-hydration' && newValue === null) {
      this.hydrate()
    } else if (name === 'playing') {
      this.handlePlayingAttributeChange(oldValue, newValue)
    }
  }

  handlePlayingAttributeChange(oldValue, newValue) {
    if (oldValue === null && newValue === '') {
      this.dispatchEvent(new CustomEvent('media:play', { bubbles: true }))
    } else if (newValue === null) {
      this.dispatchEvent(new CustomEvent('media:pause', { bubbles: true }))
    }
  }

  play() {
    this.pausedByUser = false

    if (this.playing) return
    this.player.play()
    this.playingWhenLastViewed = true
  }

  pause() {
    this.pausedByUser = true

    if (!this.playing) return
    this.player.pause()
  }

  getPlayerTarget() {
    throw new Error('getPlayerTarget must be implemented in a subclass')
  }

  playerHandler(target, prop) {
    throw new Error('playerHandler must be implemented in a subclass')
  }

  get playing() {
    return this.hasAttribute('playing')
  }

  get autoplay() {
    return this.hasAttribute('autoplay')
  }
}