/**
 * @file slider.js
 */
從 '../component.js' 導入組件;
import * as Dom from '../utils/dom.js';
從'../utils/obj'導入{assign};
從 '../utils/browser.js' 導入 {IS_CHROME};
從 '../utils/clamp.js' 導入夾具;
從“鍵碼”導入鍵碼;

/**
 * 滑塊的基本功能。可以是垂直的也可以是水平的。
 * 例如視頻上的音量條或搜索條是一個滑塊。
 *
 * @extends 組件
 */
類滑塊擴展組件{

  /**
 * 創建這個類的一個實例
 *
 * @param {Player} 播放器
 * 此類應附加到的 `Player`。
 *
 * @param {對象} [選項]
 * 播放器選項的鍵/值存儲。
 */
  構造函數(播放器,選項){
    超級(播放器,選項);

    this.handleMouseDown_ = (e) => this.handleMouseDown(e);
    this.handleMouseUp_ = (e) => this.handleMouseUp(e);
    this.handleKeyDown_ = (e) => this.handleKeyDown(e);
    this.handleClick_ = (e) => this.handleClick(e);
    this.handleMouseMove_ = (e) => this.handleMouseMove(e);
    this.update_ = (e) => this.update(e);

    // 將屬性名稱設置為 bar 以匹配正在查找的子 Slider 類
    this.bar = this.getChild(this.options_.barName);

    // 根據滑塊類型在滑塊上設置水平或垂直類
    this.vertical(!!this.options_.vertical);

    這個。啟用();
  }

  /**
   * 當前是否為此滑塊啟用了控件。
   *
   * @return {布爾值}
   * 如果啟用控件則為 true,否則為 false
   */
  啟用(){
    返回 this.enabled_;
  }

  /**
   * 如果禁用此滑塊,則啟用此滑塊的控件
   */
  使能夠() {
    如果(this.enabled()){
      返回;
    }

    this.on('mousedown', this.handleMouseDown_);
    this.on('touchstart', this.handleMouseDown_);
    this.on('keydown', this.handleKeyDown_);
    this.on('點擊', this.handleClick_);

    // TODO:已棄用,controlsvisible 似乎沒有被觸發
    this.on(this.player_, 'controlsvisible', this.update);

    如果(this.playerEvent){
      this.on(this.player_, this.playerEvent, this.update);
    }

    this.removeClass('禁用');
    this.setAttribute('tabindex', 0);

    this.enabled_ = true;
  }

  /**
   * 禁用此滑塊的控件(如果已啟用)
   */
  禁用(){
    如果(!this.enabled()){
      返回;
    }
    const doc = this.bar.el_.ownerDocument;

    this.off('mousedown', this.handleMouseDown_);
    this.off('touchstart', this.handleMouseDown_);
    this.off('keydown', this.handleKeyDown_);
    this.off('點擊', this.handleClick_);
    this.off(this.player_, 'controlsvisible', this.update_);
    this.off(doc, 'mousemove', this.handleMouseMove_);
    this.off(doc, 'mouseup', this.handleMouseUp_);
    this.off(doc, 'touchmove', this.handleMouseMove_);
    this.off(doc, 'touchend', this.handleMouseUp_);
    this.removeAttribute('tabindex');

    this.addClass('禁用');

    如果(this.playerEvent){
      this.off(this.player_, this.playerEvent, this.update);
    }
    this.enabled_ = false;
  }

  /**
   * 創建 `Slider` 的 DOM 元素。
   *
   * @param {string} 類型
   * 要創建的元素類型。
   *
   * @param {對象} [道具={}]
   * 對象形式的屬性列表。
   *
   * @param {對象} [屬性={}]
   * 對象形式的屬性列表。
   *
   * @return {元素}
   * 被創建的元素。
   */
  createEl(type, props = {}, attributes = {}) {
    // 將滑塊元素類添加到所有子類
    props.className = props.className + 'vjs-slider';
    道具=分配({
      選項卡索引: 0
    }, 道具);

    屬性=分配({
      '角色':'滑塊',
      'aria-valuenow':0,
      'aria-valuemin':0,
      'aria-valuemax':100,
      '標籤索引': 0
    }, 屬性);

    返回 super.createEl(類型,道具,屬性);
  }

  /**
   * 處理 `Slider` 上的 `mousedown` 或 `touchstart` 事件。
   *
   * @param {EventTarget~Event} 事件
   * 觸發此功能的 `mousedown` 或 `touchstart` 事件
   *
   * @listens mousedown
   * @listens touchstart
   * @fires Slider#slideractive
   */
  handleMouseDown(事件){
    const doc = this.bar.el_.ownerDocument;

    如果 (event.type === 'mousedown') {
      事件.preventDefault();
    }
    // 不要在 Chrome 中的 touchstart 上調用 preventDefault()
    // 避免控制台警告。使用“觸摸動作:無”風格
    // 而是為了防止意外滾動。
    // https://developers.google.com/web/updates/2017/01/scrolling-intervention
    如果 (event.type === 'touchstart' && !IS_CHROME) {
      事件.preventDefault();
    }
    Dom.blockTextSelection();

    this.addClass('vjs-sliding');
    /**
     * 滑塊處於活動狀態時觸發
     *
     * @event Slider#slideractive
     * @type {EventTarget~Event}
     */
    this.trigger('slideractive');

    this.on(doc, 'mousemove', this.handleMouseMove_);
    this.on(doc, 'mouseup', this.handleMouseUp_);
    this.on(doc, 'touchmove', this.handleMouseMove_);
    this.on(doc, 'touchend', this.handleMouseUp_);

    this.handleMouseMove(事件,真);
  }

  /**
   * 處理此 `Slider` 上的 `mousemove`、`touchmove` 和 `mousedown` 事件。
   * `mousemove` 和 `touchmove` 事件只會在
   * `mousedown` 和 `touchstart`。這是由於 {@link Slider#handleMouseDown} 和
   * {@link Slider#handleMouseUp}。
   *
   * @param {EventTarget~Event} 事件
   * 觸發的 `mousedown`、`mousemove`、`touchstart` 或 `touchmove` 事件
   * 這個函數
   * @param {boolean} mouseDown 這是一個標誌,如果直接調用 `handleMouseMove` 應該設置為 true。它允許我們跳過那些在按下鼠標時不應該發生但在常規鼠標移動處理程序中應該發生的事情。默認為假。
   *
   * @listens 鼠標移動
   * @listens touchmove
   */
  handleMouseMove(事件){}

  /**
   * 處理 `Slider` 上的 `mouseup` 或 `touchend` 事件。
   *
   * @param {EventTarget~Event} 事件
   * 觸發此功能的 `mouseup` 或 `touchend` 事件。
   *
   * @listens touchend
   * @listens mouseup
   * @fires Slider#sliderinactive
   */
  handleMouseUp() {
    const doc = this.bar.el_.ownerDocument;

    Dom.unblockTextSelection();

    this.removeClass('vjs-sliding');
    /**
     * 當滑塊不再處於活動狀態時觸發。
     *
     * @event Slider#sliderinactive
     * @type {EventTarget~Event}
     */
    this.trigger('sliderinactive');

    this.off(doc, 'mousemove', this.handleMouseMove_);
    this.off(doc, 'mouseup', this.handleMouseUp_);
    this.off(doc, 'touchmove', this.handleMouseMove_);
    this.off(doc, 'touchend', this.handleMouseUp_);

    這個.更新();
  }

  /**
   * 更新 `Slider` 的進度條。
   *
   * @return {數字}
   * 進度條表示的進度百分比
   * 從 0 到 1 的數字。
   */
  更新() {
    // 在 VolumeBar init 中,我們有一個 setTimeout 用於彈出和更新的更新
    // 到執行堆棧的末尾。玩家在此之前被摧毀
    // 更新會導致錯誤
    // 如果沒有欄...
    如果 (!this.el_ || !this.bar) {
      返回;
    }

    // 將進度限制在 0 和 1 之間
    // 並且只四捨五入到小數點後四位,因為我們四捨五入到下面的兩位
    const progress = this.getProgress();

    如果(進度=== this.progress_){
      返回進度;
    }

    this.progress_ = 進度;

    this.requestNamedAnimationFrame('Slider#update', () => {
      // 設置新的條形寬度或高度
      const sizeKey = this.vertical() ? '高度寬度';

      // 轉換為 css 值的百分比
      this.bar.el().style[sizeKey] = (progress * 100).toFixed(2) + '%';
    });

    返回進度;
  }

  /**
   * 獲取應該填充的柱的百分比
   * 但夾緊且圓潤。
   *
   * @return {數字}
   * 滑塊填充的百分比
   */
  getProgress() {
    返回 Number(clamp(this.getPercent(), 0, 1).toFixed(4));
  }

  /**
   * 計算滑塊的距離
   *
   * @param {EventTarget~Event} 事件
   * 導致此函數運行的事件。
   *
   * @return {數字}
   * 滑塊的當前位置。
   * - position.x 用於垂直`Slider`s
   * - 水平 `Slider` 的 position.y
   */
  計算距離(事件){
    const position = Dom.getPointerPosition(this.el_, event);

    如果(這個。垂直()){
      返回位置.y;
    }
    返回位置.x;
  }

  /**
   * 處理 `Slider` 上的 `keydown` 事件。監視左、右、上和下
   * 方向鍵。只有當滑塊有焦點時才會調用此函數。看
   * {@link Slider#handleFocus} 和 {@link Slider#handleBlur}。
   *
   * @param {EventTarget~Event} 事件
   * 導致此函數運行的 `keydown` 事件。
   *
   * @listens 按鍵
   */
  handleKeyDown(事件){

    // 向左和向下箭頭
    if (keycode.isEventKey(event, 'Left') || keycode.isEventKey(event, 'Down')) {
      事件.preventDefault();
      事件.stopPropagation();
      這個.stepBack();

    // 向上和向右箭頭
    } else if (keycode.isEventKey(event, 'Right') || keycode.isEventKey(event, 'Up')) {
      事件.preventDefault();
      事件.stopPropagation();
      這個.stepForward();
    }其他{

      // 為不支持的鍵傳遞 keydown 處理
      super.handleKeyDown(事件);
    }
  }

  /**
   * 滑塊上點擊事件的監聽器,用於防止點擊
   * 從冒泡到父元素,如按鈕菜單。
   *
   * @param {Object} 事件
   * 導致該對象運行的事件
   */
  handleClick(事件){
    事件.stopPropagation();
    事件.preventDefault();
  }

  /**
   * 獲取/設置滑塊是否水平垂直
   *
   * @param {布爾} [布爾]
   * - 如果滑塊是垂直的,則為真,
   * - false 是水平的
   *
   * @return {布爾值}
   * - 如果滑塊是垂直的,則為真
   * - 如果滑塊是水平的,則為 false,並且獲取
   */
  垂直(布爾){
    如果(布爾===未定義){
      返回 this.vertical_ ||錯誤的;
    }

    this.vertical_ = !!bool;

    如果(this.vertical_){
      this.addClass('vjs-slider-vertical');
    }其他{
      this.addClass('vjs-slider-horizontal');
    }
  }
}

Component.registerComponent('Slider', Slider);
導出默認滑塊;