/**
 * @파일 메뉴-버튼.js
 */
'../button.js'에서 버튼 가져오기;
'../component.js'에서 컴포넌트 가져오기;
'./menu.js'에서 메뉴 가져오기;
import * as Dom from '../utils/dom.js';
import * as Events from '../utils/events.js';
'../utils/string-cases.js'에서 {toTitleCase} 가져오기;
import { IS_IOS } from '../utils/browser.js';
'글로벌/문서'에서 문서 가져오기;
'키코드'에서 키코드 가져오기;

/**
 * 팝업 {@link Menu}에 대한 `MenuButton` 클래스.
 *
 * @extends 컴포넌트
 */
MenuButton 클래스는 구성 요소 {를 확장합니다.

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

    this.menuButton_ = new Button(플레이어, 옵션);

    this.menuButton_.controlText(this.controlText_);
    this.menuButton_.el_.setAttribute('aria-haspopup', 'true');

    // 래퍼가 아닌 버튼에 buildCSSClass 값을 추가합니다.
    const buttonClass = Button.prototype.buildCSSClass();

    this.menuButton_.el_.className = this.buildCSSClass() + ' ' + buttonClass;
    this.menuButton_.removeClass('vjs-control');

    this.addChild(this.menuButton_);

    this.update();

    this.enabled_ = 참;

    const handleClick = (e) => this.handleClick(e);

    this.handleMenuKeyUp_ = (e) => this.handleMenuKeyUp(e);

    this.on(this.menuButton_, 'tap', handleClick);
    this.on(this.menuButton_, 'click', handleClick);
    this.on(this.menuButton_, 'keydown', (e) => this.handleKeyDown(e));
    this.on(this.menuButton_, 'mouseenter', () => {
      this.addClass('vjs-hover');
      this.menu.show();
      Events.on(document, 'keyup', this.handleMenuKeyUp_);
    });
    this.on('마우스리브', (e) => this.handleMouseLeave(e));
    this.on('키다운', (e) => this.handleSubmenuKeyDown(e));
  }

  /**
   * 항목의 현재 상태에 따라 메뉴를 업데이트합니다.
   */
  업데이트() {
    const menu = this.createMenu();

    if (this.menu) {
      this.menu.dispose();
      this.removeChild(this.menu);
    }

    this.menu = 메뉴;
    this.addChild(메뉴);

    /**
     * 메뉴 버튼의 상태 추적
     *
     * @type {부울}
     * @사적인
     */
    this.buttonPressed_ = 거짓;
    this.menuButton_.el_.setAttribute('aria-expanded', 'false');

    if (이 항목 && 이.항목.길이 < = this.hideThreshold_) {
      this.hide();
      this.menu.contentEl_.removeAttribute('role');

    } else {
      this.show();
      this.menu.contentEl_.setAttribute('역할', '메뉴');
    }
  }

  /**
   * 메뉴를 생성하고 여기에 모든 항목을 추가합니다.
   *
   * @return {메뉴}
   * 구성된 메뉴
   */
  createMenu() {
    const menu = new Menu(this.player_, { menuButton: this });

    /**
     * 항목 수가 이 임계값보다 작거나 같으면 메뉴를 숨깁니다. 이것은 기본값
     *를 0으로 설정하고 메뉴에 숨길 수 있는 항목을 추가할 때마다 항목을 증가시킵니다. 우리는 나열
     * 'createMenu'를 실행할 때마다 값을 재설정해야 하기 때문에 여기에 있습니다.
     *
     * @보호됨
     * @type {숫자}
     */
    this.hideThreshold_ = 0;

    // 제목 목록 항목을 맨 위에 추가
    if (this.options_.title) {
      const titleEl = Dom.createEl('li', {
        className: 'vjs-menu-title',
        textContent: toTitleCase(this.options_.title),
        탭 인덱스: -1
      });

      const titleComponent = new Component(this.player_, {el: titleEl});

      menu.addItem(titleComponent);
    }

    this.items = this.createItems();

    if(이 항목) {
      // 메뉴에 메뉴 항목 추가
      에 대한 (하자 i = 0; i < this.items.length; i++) {
        menu.addItem(this.items[i]);
      }
    }

    돌아가는 메뉴;
  }

  /**
   * 메뉴 항목 목록을 만듭니다. 각 하위 클래스에 따라 다릅니다.
   *
   * @추상적인
   */
  createItems() {}

  /**
   * `MenuButtons`의 DOM 요소를 생성합니다.
   *
   * @return {요소}
   * 생성되는 요소.
   */
  createEl() {
    return super.createEl('div', {
      className: this.buildWrapperCSSClass()
    }, {
    });
  }

  /**
   * 하위 구성 요소가 래퍼 요소에 대한 CSS 클래스 이름을 쌓을 수 있도록 허용
   *
   * @return {문자열}
   * 구성된 래퍼 DOM `className`
   */
  buildWrapperCSSClass() {
    let menuButtonClass = 'vjs-메뉴 버튼';

    // 인라인 옵션이 전달되면 서로 다른 스타일을 모두 사용하려고 합니다.
    if (this.options_.inline === 참) {
      menuButtonClass += '-인라인';
    } else {
      menuButtonClass += '-팝업';
    }

    // 할 것: 이것이 필요하지 않도록 CSS를 수정하십시오.
    const buttonClass = Button.prototype.buildCSSClass();

    `vjs-menu-button ${menuButtonClass} ${buttonClass} ${super.buildCSSClass()}` 반환;
  }

  /**
   * 기본 DOM `className`을 빌드합니다.
   *
   * @return {문자열}
   * 이 개체의 DOM `className`입니다.
   */
  buildCSSClass() {
    let menuButtonClass = 'vjs-메뉴 버튼';

    // 인라인 옵션이 전달되면 서로 다른 스타일을 모두 사용하려고 합니다.
    if (this.options_.inline === 참) {
      menuButtonClass += '-인라인';
    } else {
      menuButtonClass += '-팝업';
    }

    `vjs-menu-button ${menuButtonClass} ${super.buildCSSClass()}` 반환;
  }

  /**
   * 접근성에 사용될 현지화된 제어 텍스트를 가져오거나 설정합니다.
   *
   * > 메모: 내부 `menuButton_` 요소에서 가져옵니다.
   *
   * @param {문자열} [텍스트]
   * 요소에 대한 제어 텍스트.
   *
   * @param {요소} [el=this.menuButton_.el()]
   * 제목을 설정할 요소.
   *
   * @return {문자열}
   * - 가져올 때 제어 텍스트
   */
  controlText(텍스트, el = this.menuButton_.el()) {
    return this.menuButton_.controlText(text, el);
  }

  /**
   * `메뉴 버튼`과 모든 자식 구성 요소를 폐기하십시오.
   */
  폐기() {
    this.handleMouseLeave();
    super.dispose();
  }

  /**
   * `MenuButton` 클릭을 처리합니다.
   * 이것이 호출되는 인스턴스는 {@link ClickableComponent#handleClick}을 참조하세요.
   *
   * @param {EventTarget~Event} 이벤트
   * 이 함수를 실행하게 만든 `keydown`, `tap` 또는 `click` 이벤트
   * 라고 불리는.
   *
   * @listens 탭
   * @듣기 클릭
   */
  handleClick(이벤트) {
    if (this.buttonPressed_) {
      this.unpressButton();
    } else {
      this.pressButton();
    }
  }

  /**
   * `MenuButton`에 대한 `mouseleave` 처리.
   *
   * @param {EventTarget~Event} 이벤트
   * 이 함수를 호출한 `mouseleave` 이벤트.
   *
   * @listens mouseleave
   */
  handleMouseLeave(이벤트) {
    this.removeClass('vjs-hover');
    Events.off(문서, '키업', this.handleMenuKeyUp_);
  }

  /**
   * 이 요소가 아닌 실제 버튼에 포커스 설정
   */
  집중하다() {
    this.menuButton_.focus();
  }

  /**
   * 이 요소가 아닌 실제 버튼에서 포커스 제거
   */
  블러() {
    this.menuButton_.blur();
  }

  /**
   * `MenuButton`의 탭, 이스케이프, 아래쪽 화살표 및 위쪽 화살표 키를 처리합니다. 보다
   * 이것이 호출되는 인스턴스에 대한 {@link ClickableComponent#handleKeyDown}.
   *
   * @param {EventTarget~Event} 이벤트
   * 이 함수를 호출한 `keydown` 이벤트.
   *
   * @listens 키다운
   */
  handleKeyDown(이벤트) {

    // 이스케이프 또는 탭 '버튼'을 누름 해제
    if (keycode.isEventKey(event, 'Esc') || keycode.isEventKey(event, 'Tab')) {
      if (this.buttonPressed_) {
        this.unpressButton();
      }

      // Tab 키의 경우 preventDefault를 사용하지 마십시오. 여전히 포커스를 잃고 싶습니다.
      if (!keycode.isEventKey(event, 'Tab')) {
        event.preventDefault();
        // 포커스를 다시 메뉴 버튼의 버튼으로 설정합니다.
        this.menuButton_.focus();
      }
    // 위쪽 화살표 또는 아래쪽 화살표도 버튼을 '누르면' 메뉴가 열립니다.
    } else if (keycode.isEventKey(event, 'Up') || keycode.isEventKey(event, 'Down')) {
      if (!this.buttonPressed_) {
        event.preventDefault();
        this.pressButton();
      }
    }
  }

  /**
   * `MenuButton`에서 `keyup` 이벤트를 처리합니다. 이에 대한 리스너가 다음에 추가됩니다.
   * 생성자.
   *
   * @param {EventTarget~Event} 이벤트
   * 키 누르기 이벤트
   *
   * @listens 키업
   */
  handleMenuKeyUp(이벤트) {
    // 이스케이프는 팝업 메뉴를 숨깁니다.
    if (keycode.isEventKey(event, 'Esc') || keycode.isEventKey(event, 'Tab')) {
      this.removeClass('vjs-hover');
    }
  }

  /**
   * 이 메서드 이름은 이제 `handleSubmenuKeyDown`에 위임됩니다. 이것은 의미합니다
   * `handleSubmenuKeyPress`를 호출하는 사람은 메서드 호출을 볼 수 없습니다.
   * 그만 일해.
   *
   * @param {EventTarget~Event} 이벤트
   * 이 함수를 호출한 이벤트.
   */
  handleSubmenuKeyPress(이벤트) {
    this.handleSubmenuKeyDown(이벤트);
  }

  /**
   * 하위 메뉴에서 `keydown` 이벤트를 처리합니다. 이에 대한 리스너가 다음에 추가됩니다.
   * 생성자.
   *
   * @param {EventTarget~Event} 이벤트
   * 키 누르기 이벤트
   *
   * @listens 키다운
   */
  handleSubmenuKeyDown(이벤트) {
    // 이스케이프 또는 탭 '버튼'을 누름 해제
    if (keycode.isEventKey(event, 'Esc') || keycode.isEventKey(event, 'Tab')) {
      if (this.buttonPressed_) {
        this.unpressButton();
      }
      // Tab 키의 경우 preventDefault를 사용하지 마십시오. 여전히 포커스를 잃고 싶습니다.
      if (!keycode.isEventKey(event, 'Tab')) {
        event.preventDefault();
        // 포커스를 다시 메뉴 버튼의 버튼으로 설정합니다.
        this.menuButton_.focus();
      }
    } else {
      // 메모: 처리되지 않은 상태로 통과하지 않는 특수한 경우입니다.
      // Component 핸들러까지의 keydown 이벤트입니다.
      // `MenuItem`의 keydown 처리를 종료합니다.
      // 이미 사용하지 않은 키를 전달하는 `메뉴`에서.
    }
  }

  /**
   * 현재 `MenuButton`을 눌린 상태로 만듭니다.
   */
  버튼을 누르시오() {
    if (이.활성화_) {
      this.buttonPressed_ = 참;
      this.menu.show();
      this.menu.lockShowing();
      this.menuButton_.el_.setAttribute('aria-expanded', 'true');

      // 하위 메뉴에 포커스를 설정합니다. 단, iOS는 예외입니다.
      // 플레이어가 iframe에 있을 때 원하지 않는 스크롤 동작
      만약 (IS_IOS && Dom.isInFrame()) {
        // 메뉴가 포커스되지 않도록 일찍 돌아갑니다.
        반품;
      }

      this.menu.focus();
    }
  }

  /**
   * 현재 `MenuButton`을 눌린 상태에서 해제합니다.
   */
  unpressButton() {
    if (이.활성화_) {
      this.buttonPressed_ = 거짓;
      this.menu.unlockShowing();
      this.menu.hide();
      this.menuButton_.el_.setAttribute('aria-expanded', 'false');
    }
  }

  /**
   * `MenuButton`을 비활성화합니다. 클릭을 허용하지 마십시오.
   */
  장애를 입히다() {
    this.unpressButton();

    this.enabled_ = 거짓;
    this.addClass('vjs-disabled');

    this.menuButton_.disable();
  }

  /**
   * `MenuButton`을 활성화합니다. 클릭하도록 허용합니다.
   */
  할 수 있게 하다() {
    this.enabled_ = 참;
    this.removeClass('vjs-disabled');

    this.menuButton_.enable();
  }
}

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