/**
* @파일 메뉴-버튼.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 내보내기;