/**
 * @file seek-bar.js
 */
'../../slider/slider.js'에서 슬라이더 가져오기;
'../../component.js'에서 컴포넌트 가져오기;
'../../utils/browser.js'에서 {IS_IOS, IS_ANDROID} 가져오기;
import * as Dom from '../../utils/dom.js';
import * as Fn from '../../utils/fn.js';
import formatTime from '../../utils/format-time.js';
'../../utils/promise'에서 {silencePromise} 가져오기;
'키코드'에서 키코드 가져오기;
'글로벌/문서'에서 문서 가져오기;

import './load-progress-bar.js';
import './play-progress-bar.js';
import './mouse-time-display.js';

// `step*` 함수가 타임라인을 이동하는 시간(초)입니다.
const STEP_SECONDS = 5;

// PgUp/PgDown이 타임라인을 이동하는 STEP_SECONDS의 승수.
const PAGE_KEY_MULTIPLIER = 12;

/**
 * 진행률 표시줄에 대한 검색 막대 및 컨테이너. {@link PlayProgressBar} 사용
 * `bar`로.
 *
 * @extends 슬라이더
 */
클래스 SeekBar 확장 슬라이더 {

  /**
   * 이 클래스의 인스턴스를 만듭니다.
   *
   * @param {플레이어} 플레이어
   * 이 클래스가 연결되어야 하는 `Player`.
   *
   * @param {객체} [옵션]
   * 플레이어 옵션의 키/값 저장소.
   */
  생성자(플레이어, 옵션) {
    super(플레이어, 옵션);
    this.setEventHandlers_();
  }

  /**
   * 이벤트 핸들러 설정
   *
   * @사적인
   */
  setEventHandlers_() {
    this.update_ = Fn.bind(this, this.update);
    this.update = Fn.throttle(this.update_, Fn.UPDATE_REFRESH_INTERVAL);

    this.on(this.player_, ['종료', 'durationchange', 'timeupdate'], this.update);
    if (this.player_.liveTracker) {
      this.on(this.player_.liveTracker, 'liveedgechange', this.update);
    }

    // 재생 시 재생 진행률 표시줄을 원활하게 업데이트하도록 합시다.
    // 간격을 통해
    this.updateInterval = null;

    this.enableIntervalHandler_ = (e) => this.enableInterval_(e);
    this.disableIntervalHandler_ = (e) => this.disableInterval_(e);

    this.on(this.player_, ['playing'], this.enableIntervalHandler_);

    this.on(this.player_, ['종료', '일시정지', '대기'], this.disableIntervalHandler_);

    // 문서가 숨겨져 있으면 재생 진행률을 업데이트할 필요가 없습니다.
    // 또한 이로 인해 CPU가 급증하고 결국 IE11에서 페이지가 충돌합니다.
    if (문서에 '숨겨진' && 문서의 'visibilityState') {
      this.on(문서, 'visibilitychange', this.toggleVisibility_);
    }
  }

  toggleVisibility_(e) {
    if (document.visibilityState === '숨김') {
      this.cancelNamedAnimationFrame('SeekBar#update');
      this.cancelNamedAnimationFrame('슬라이더#업데이트');
      this.disableInterval_(e);
    } else {
      if (!this.player_.ended() && !this.player_.paused()) {
        this.enableInterval_();
      }

      // 방금 페이지로 다시 전환했고 누군가 보고 있을 수 있으므로 최대한 빨리 업데이트합니다.
      this.update();
    }
  }

  enableInterval_() {
    if (이.업데이트 간격) {
      반품;

    }
    this.updateInterval = this.setInterval(this.update, Fn.UPDATE_REFRESH_INTERVAL);
  }

  disableInterval_(e) {
    if (this.player_.liveTracker && this.player_.liveTracker.isLive() && 이자형 && e.type !== '종료됨') {
      반품;
    }

    if (!this.updateInterval) {
      반품;
    }

    this.clearInterval(this.updateInterval);
    this.updateInterval = null;
  }

  /**
   * `Component`의 DOM 요소 생성
   *
   * @return {요소}
   * 생성된 요소입니다.
   */
  createEl() {
    return super.createEl('div', {
      className: 'vjs-progress-holder'
    }, {
      'aria-label': this.localize('진행률 표시줄')
    });
  }

  /**
   * 이 기능은 재생 진행률 표시줄과 접근성을 업데이트합니다.
   * 전달되는 속성.
   *
   * @param {이벤트대상~이벤트} [이벤트]
   * 실행을 유발한 `timeupdate` 또는 `ended` 이벤트.
   *
   * @listens Player#timeupdate
   *
   * @return {숫자}
   * 0-1 숫자의 현재 백분율
   */
  업데이트(이벤트) {
    // 탭이 숨겨져 있는 동안 업데이트 무시
    if (document.visibilityState === '숨김') {
      반품;
    }

    const 퍼센트 = super.update();

    this.requestNamedAnimationFrame('SeekBar#update', () => {
      const currentTime = this.player_.ended() ?
        this.player_.duration() : this.getCurrentTime_();
      const liveTracker = this.player_.liveTracker;
      let duration = this.player_.duration();

      if (liveTracker && liveTracker.isLive()) {
        기간 = this.player_.liveTracker.liveCurrentTime();
      }

      if (this.percent_ !== 퍼센트) {
        // 진행률 표시줄의 기계 판독 가능 값(완료율)
        this.el_.setAttribute('aria-valuenow', (퍼센트 * 100).toFixed(2));
        this.percent_ = 퍼센트;
      }

      if (this.currentTime_ !== currentTime || this.duration_ !== 기간) {
        // 진행률 표시줄의 사람이 읽을 수 있는 값(완료 시간)
        this.el_.setAttribute(
          '아리아 값 텍스트',
          this.localize(
            '진행률 표시줄 타이밍: currentTime={1} duration={2}',
            [형식시간(현재시간, 기간),
              formatTime(기간, 기간)],
            {2} 중 '{1}'
          )
        );

        this.currentTime_ = 현재시간;
        this.duration_ = 기간;
      }

      // 진행률 표시줄 시간 툴팁을 현재 시간으로 업데이트합니다.
      if (이.바) {
        this.bar.update(Dom.getBoundingClientRect(this.el()), this.getProgress());
      }
    });

    퍼센트 반환;
  }

  /**
   * liveThreshold로 인해 검색된 것처럼 보이는 것을 방지합니다.
   * 사용자 관점에서 발생하지 않습니다.
   *
   * @param {숫자} ct
   * 탐색할 현재 시간
   */
  userSeek_(ct) {
    if (this.player_.liveTracker && this.player_.liveTracker.isLive()) {
      this.player_.liveTracker.nextSeekedFromUser();
    }

    this.player_.currentTime(ct);
  }

  /**
   * 현재 시간의 값을 가져오지만 부드러운 스크러빙을 허용합니다.
   * 플레이어가 따라갈 수 없을 때.
   *
   * @return {숫자}
   * 표시할 현재 시간 값
   *
   * @사적인
   */
  getCurrentTime_() {
    return (this.player_.scrubbing()) ?
      this.player_.getCache().currentTime :
      this.player_.currentTime();
  }

  /**
   * 지금까지 재생된 미디어의 비율을 가져옵니다.
   *
   * @return {숫자}
   * 지금까지 재생된 미디어의 비율(0에서 1).
   */
  getPercent() {
    const currentTime = this.getCurrentTime_();
    퍼센트하자;
    const liveTracker = this.player_.liveTracker;

    if (liveTracker && liveTracker.isLive()) {
      퍼센트 = (currentTime - liveTracker.seekableStart()) / liveTracker.liveWindow();

      // 라이브 에지에서 백분율이 변경되지 않도록 방지
      if (liveTracker.atLiveEdge()) {
        퍼센트 = 1;
      }
    } else {
      퍼센트 = currentTime / this.player_.duration();
    }

    퍼센트 반환;
  }

  /**
   * 검색 바에서 마우스를 아래로 처리
   *
   * @param {EventTarget~Event} 이벤트
   * 이것을 실행하게 만든 `mousedown` 이벤트.
   *
   * @listens mousedown
   */
  handleMouseDown(이벤트) {
    if (!Dom.isSingleLeftClick(이벤트)) {
      반품;
    }

    // progress-control.js에서 이중 실행을 방지하기 위해 이벤트 전파 중지
    event.stopPropagation();

    this.videoWasPlaying = !this.player_.paused();
    this.player_.pause();

    super.handleMouseDown(event);
  }

  /**
   * 검색 바에서 마우스 이동 처리
   *
   * @param {EventTarget~Event} 이벤트
   * 이것을 실행하게 만든 `mousemove` 이벤트.
   * @param {boolean} mouseDown `handleMouseMove`가 직접 호출되는 경우 true로 설정되어야 하는 플래그입니다. 이것은 우리가 마우스를 눌렀을 때 발생하지 않아야 하지만 일반 마우스 이동 처리기에서 발생해야 하는 일을 건너뛸 수 있게 해줍니다. 기본값은 false
   *
   * @listens mousemove
   */
  handleMouseMove(이벤트, mouseDown = false) {
    if (!Dom.isSingleLeftClick(이벤트)) {
      반품;
    }

    if (!mouseDown && !this.player_.scrubbing()) {
      this.player_.scrubbing(true);
    }

    newTime하자;
    const 거리 = this.calculateDistance(event);
    const liveTracker = this.player_.liveTracker;

    if (!liveTracker || !liveTracker.isLive()) {
      newTime = 거리 * this.player_.duration();

      // 스크러빙하는 동안 비디오가 종료되지 않도록 합니다.
      if (newTime === this.player_.duration()) {
        newTime = newTime - 0.1;
      }
    } else {

      만약 (거리 > = 0.99) {
        liveTracker.seekToLiveEdge();
        반품;
      }
      const seekableStart = liveTracker.seekableStart();
      const seekableEnd = liveTracker.liveCurrentTime();

      newTime = seekableStart + (거리 * liveTracker.liveWindow());

      // 스크러빙하는 동안 비디오가 종료되지 않도록 합니다.
      if (newTime > = seekableEnd) {
        newTime = seekableEnd;
      }

      // currentTime이 적지 않도록 정밀도 차이를 보상합니다.
      // 탐색 가능한 시작보다
      if (newTime < = 탐색 가능한 시작) {
        newTime = seekableStart + 0.1;
      }

      // 안드로이드에서 seekableEnd는 때때로 Infinity가 될 수 있습니다.
      // 이렇게 하면 newTime이 Infinity가 됩니다.
      // 유효한 currentTime이 아닙니다.
      if (newTime === 무한대) {
        반품;
      }
    }

    // 새로운 시간 설정(플레이어에게 새로운 시간을 찾도록 지시)
    this.userSeek_(newTime);
  }

  할 수 있게 하다() {
    슈퍼.활성화();
    const mouseTimeDisplay = this.getChild('mouseTimeDisplay');

    if (!mouseTimeDisplay) {
      반품;
    }

    mouseTimeDisplay.show();
  }

  장애를 입히다() {
    슈퍼.비활성화();
    const mouseTimeDisplay = this.getChild('mouseTimeDisplay');

    if (!mouseTimeDisplay) {
      반품;
    }

    mouseTimeDisplay.hide();
  }

  /**
   * 검색 바에서 핸들 마우스 업
   *
   * @param {EventTarget~Event} 이벤트
   * 이것을 실행하게 만든 `mouseup` 이벤트.
   *
   * @listens mouseup
   */
  handleMouseUp(이벤트) {
    super.handleMouseUp(이벤트);

    // progress-control.js에서 이중 실행을 방지하기 위해 이벤트 전파 중지
    경우 (이벤트) {
      event.stopPropagation();
    }
    this.player_.scrubbing(false);

    /**
     * 검색을 완료하고 시간이 변경되었기 때문에 timeupdate를 트리거합니다.
     * 시간 표시 시간을 맞추기 위해 플레이어가 일시 중지된 경우에 특히 유용합니다.
     *
     * @event Tech#timeupdate
     * @type {이벤트대상~이벤트}
     */
    this.player_.trigger({ type: 'timeupdate', target: this, manualTriggered: true });
    if (this.videoWasPlaying) {
      침묵 약속(this.player_.play());
    } else {
      // 검색을 마쳤으며 시간이 변경되었습니다.
      // 플레이어가 일시 중지된 경우 탐색 표시줄에 정확한 시간을 표시하는지 확인합니다.
      this.update_();
    }
  }

  /**
   * 키보드만 사용하는 사용자를 위해 더 빠르게 빨리 앞으로 이동
   */
  앞으로 단계() {
    this.userSeek_(this.player_.currentTime() + STEP_SECONDS);
  }

  /**
   * 키보드만 사용하는 사용자를 위해 더 빠르게 되감기
   */
  스텝백() {
    this.userSeek_(this.player_.currentTime() - STEP_SECONDS);
  }

  /**
   * 플레이어의 재생 상태를 토글합니다.
   * 탐색바에서 엔터나 스페이스바를 사용했을 때 호출됩니다.
   *
   * @param {EventTarget~Event} 이벤트
   * 이 함수를 호출하게 만든 `keydown` 이벤트
   *
   */
  핸들액션(이벤트) {
    if (this.player_.paused()) {
      this.player_.play();
    } else {
      this.player_.pause();
    }
  }

  /**
   * 이 SeekBar에 포커스가 있고 키가 눌렸을 때 호출됩니다.
   * 다음 키를 지원합니다.
   *
   * Space 또는 Enter 키는 클릭 이벤트를 발생시킵니다.
   * 홈 키는 타임라인의 시작 부분으로 이동합니다.
   * End 키는 타임라인의 끝으로 이동합니다.
   * 숫자 "0"에서 "9" 키는 0%, 10%로 이동합니다... 타임라인의 80%, 90%
   * PageDown 키는 ArrowDown보다 더 큰 단계 뒤로 이동합니다.
   * PageUp 키는 큰 단계 앞으로 이동합니다.
   *
   * @param {EventTarget~Event} 이벤트
   * 이 함수를 호출한 `keydown` 이벤트.
   *
   * @listens 키다운
   */
  handleKeyDown(이벤트) {
    const liveTracker = this.player_.liveTracker;

    if (keycode.isEventKey(event, 'Space') || keycode.isEventKey(event, 'Enter')) {
      event.preventDefault();
      event.stopPropagation();
      this.handleAction(이벤트);
    } 그렇지 않으면 (keycode.isEventKey(이벤트, '홈')) {
      event.preventDefault();
      event.stopPropagation();
      this.userSeek_(0);
    } 그렇지 않으면 (keycode.isEventKey(event, 'End')) {
      event.preventDefault();
      event.stopPropagation();
      if (liveTracker && liveTracker.isLive()) {
        this.userSeek_(liveTracker.liveCurrentTime());
      } else {
        this.userSeek_(this.player_.duration());
      }
    } 그렇지 않으면 (/^[0-9]$/.test(키코드(이벤트))) {
      event.preventDefault();
      event.stopPropagation();
      const gotoFraction = (keycode.codes[keycode(event)] - keycode.codes['0']) * 10.0 / 100.0;

      if (liveTracker && liveTracker.isLive()) {
        this.userSeek_(liveTracker.seekableStart() + (liveTracker.liveWindow() * gotoFraction));
      } else {
        this.userSeek_(this.player_.duration() * gotoFraction);
      }
    } 그렇지 않으면 (keycode.isEventKey(event, 'PgDn')) {
      event.preventDefault();
      event.stopPropagation();
      this.userSeek_(this.player_.currentTime() - (STEP_SECONDS * PAGE_KEY_MULTIPLIER));
    } 그렇지 않으면 (keycode.isEventKey(event, 'PgUp')) {
      event.preventDefault();
      event.stopPropagation();
      this.userSeek_(this.player_.currentTime() + (STEP_SECONDS * PAGE_KEY_MULTIPLIER));
    } else {
      // 지원되지 않는 키에 대한 keydown 처리를 전달합니다.
      super.handleKeyDown(이벤트);
    }
  }

  폐기() {
    this.disableInterval_();

    this.off(this.player_, ['종료', 'durationchange', 'timeupdate'], this.update);
    if (this.player_.liveTracker) {
      this.off(this.player_.liveTracker, 'liveedgechange', this.update);
    }

    this.off(this.player_, ['playing'], this.enableIntervalHandler_);
    this.off(this.player_, ['종료', '일시정지', '대기'], this.disableIntervalHandler_);

    // 문서가 숨겨져 있으면 재생 진행률을 업데이트할 필요가 없습니다.
    // 또한 이로 인해 CPU가 급증하고 결국 IE11에서 페이지가 충돌합니다.
    if (문서에 '숨겨진' && 문서의 'visibilityState') {
      this.off(문서, 'visibilitychange', this.toggleVisibility_);
    }

    super.dispose();
  }
}

/**
 * `SeekBar`의 기본 옵션
 *
 * @type {객체}
 * @사적인
 */
SeekBar.prototype.options_ = {
  어린이들: [
    '로드프로그레스바',
    'playProgressBar'
  ],
  barName: 'playProgressBar'
};

// MouseTimeDisplay 도구 설명은 모바일 장치의 플레이어에 추가하면 안 됩니다.
만약 (!IS_IOS && !IS_ANDROID) {
  SeekBar.prototype.options_.children.splice(1, 0, 'mouseTimeDisplay');
}

Component.registerComponent('SeekBar', SeekBar);
기본 SeekBar 내보내기;