/**
* @file 菜單按鈕.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};
從'../utils/browser.js'導入{IS_IOS};
從“全局/文檔”導入文檔;
從“鍵碼”導入鍵碼;
/**
* 任何彈出菜單 {@link Menu} 的 `MenuButton` 類。
*
* @extends 組件
*/
類 MenuButton 擴展組件 {
/**
* 創建此類的一個實例。
*
* @param {Player} 播放器
* 此類應附加到的 `Player`。
*
* @param {對象} [選項={}]
* 播放器選項的鍵/值存儲。
*/
構造函數(播放器,選項= {}){
超級(播放器,選項);
this.menuButton_ = new Button(player, options);
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.enabled_ = true;
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-懸停');
這個.menu.show();
Events.on(文檔, 'keyup', this.handleMenuKeyUp_);
});
this.on('mouseleave', (e) => this.handleMouseLeave(e));
this.on('keydown', (e) => this.handleSubmenuKeyDown(e));
}
/**
* 根據項目的當前狀態更新菜單。
*/
更新() {
const menu = this.createMenu();
如果(這個。菜單){
這個.menu.dispose();
this.removeChild(this.menu);
}
this.menu = 菜單;
這個.addChild(菜單);
/**
* 跟踪菜單按鈕的狀態
*
* @type {布爾}
* @私人的
*/
this.buttonPressed_ = false;
this.menuButton_.el_.setAttribute('aria-expanded', 'false');
如果(this.items && this.items.length <= this.hideThreshold_){
這個。隱藏();
this.menu.contentEl_.removeAttribute('角色');
}其他{
這個。顯示();
this.menu.contentEl_.setAttribute('角色', '菜單');
}
}
/**
* 創建菜單並向其中添加所有項目。
*
* @return {菜單}
* 構建的菜單
*/
創建菜單(){
const menu = new Menu(this.player_, { menuButton: this });
/**
* 如果項目數小於或等於此閾值,則隱藏菜單。這默認
* 到 0,每當我們將可以隱藏的項目添加到菜單時,我們都會增加它。我們列出
* 在這裡是因為每次我們運行 `createMenu` 時我們都需要重置這個值。
*
* @protected
* @type {數字}
*/
this.hideThreshold_ = 0;
// 在頂部添加一個標題列表項
如果(this.options_.title){
const titleEl = Dom.createEl('li', {
className: 'vjs-菜單標題',
textContent: toTitleCase(this.options_.title),
選項卡索引:-1
});
const titleComponent = new Component(this.player_, {el: titleEl});
menu.addItem(titleComponent);
}
this.items = this.createItems();
如果(這個。項目){
// 添加菜單項到菜單
for (let i = 0; i < this.items.length; i++) {
menu.addItem(this.items[i]);
}
}
返回菜單;
}
/**
* 創建菜單項列表。具體到每個子類。
*
* @抽象的
*/
創建項目(){}
/**
* 創建 `MenuButtons` 的 DOM 元素。
*
* @return {元素}
* 被創建的元素。
*/
創建El() {
返回 super.createEl('div', {
類名:this.buildWrapperCSSClass()
},{
});
}
/**
* 允許子組件為 wrapper 元素堆疊 CSS 類名
*
* @return {字符串}
* 構造的包裝器 DOM `className`
*/
buildWrapperCSSClass() {
讓 menuButtonClass = 'vjs-menu-button';
// 如果傳遞了內聯選項,我們希望完全使用不同的樣式。
如果(this.options_.inline === true){
menuButtonClass += '-inline';
}其他{
menuButtonClass += '-popup';
}
// 去做:修復 CSS,這樣就沒有必要了
const buttonClass = Button.prototype.buildCSSClass();
返回`vjs-menu-button ${menuButtonClass} ${buttonClass} ${super.buildCSSClass()}`;
}
/**
* 構建默認的 DOM `className`。
*
* @return {字符串}
* 此對象的 DOM `className`。
*/
buildCSSClass() {
讓 menuButtonClass = 'vjs-menu-button';
// 如果傳遞了內聯選項,我們希望完全使用不同的樣式。
如果(this.options_.inline === true){
menuButtonClass += '-inline';
}其他{
menuButtonClass += '-popup';
}
返回`vjs-menu-button ${menuButtonClass} ${super.buildCSSClass()}`;
}
/**
* 獲取或設置將用於輔助功能的本地化控製文本。
*
* > 注意:這將來自內部的 `menuButton_` 元素。
*
* @param {字符串} [文本]
* 元素的控製文本。
*
* @param {Element} [el=this.menuButton_.el()]
* 設置標題的元素。
*
* @return {字符串}
* - 獲取時的控製文本
*/
controlText(text, el = this.menuButton_.el()) {
返回 this.menuButton_.controlText(text, el);
}
/**
* 處理 `menu-button` 和所有子組件。
*/
處置(){
this.handleMouseLeave();
super.dispose();
}
/**
* 處理對 `MenuButton` 的點擊。
* 請參閱 {@link ClickableComponent#handleClick} 以了解調用此方法的實例。
*
* @param {EventTarget~Event} 事件
* 導致此功能被執行的 `keydown`、`tap` 或 `click` 事件
* 打電話。
*
* @listens 水龍頭
* @listens 點擊
*/
handleClick(事件){
如果(this.buttonPressed_){
這個.unpressButton();
}其他{
這個.pressButton();
}
}
/**
* 為 `MenuButton` 處理 `mouseleave`。
*
* @param {EventTarget~Event} 事件
* 導致調用此函數的 `mouseleave` 事件。
*
* @listens 鼠標離開
*/
handleMouseLeave(事件){
this.removeClass('vjs-hover');
Events.off(文檔, 'keyup', this.handleMenuKeyUp_);
}
/**
* 將焦點設置到實際的按鈕,而不是這個元素
*/
重點() {
這個.menuButton_.focus();
}
/**
* 從實際按鈕上移除焦點,而不是這個元素
*/
模糊(){
這個.menuButton_.blur();
}
/**
* 處理 `MenuButton` 的製表符、轉義鍵、向下箭頭和向上箭頭鍵。看
* {@link ClickableComponent#handleKeyDown} 用於調用它的實例。
*
* @param {EventTarget~Event} 事件
* 導致調用此函數的 `keydown` 事件。
*
* @listens 按鍵
*/
handleKeyDown(事件){
// Escape 或 Tab 取消按下“按鈕”
if (keycode.isEventKey(event, 'Esc') || keycode.isEventKey(event, 'Tab')) {
如果(this.buttonPressed_){
這個.unpressButton();
}
// 不要阻止 Tab 鍵的默認值 - 我們仍然想失去焦點
如果 (!keycode.isEventKey(event, 'Tab')) {
事件.preventDefault();
// 將焦點設置回菜單按鈕的按鈕
這個.menuButton_.focus();
}
// 向上箭頭或向下箭頭也“按下”按鈕以打開菜單
} else if (keycode.isEventKey(event, 'Up') || keycode.isEventKey(event, 'Down')) {
如果(!this.buttonPressed_){
事件.preventDefault();
這個.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(事件){
// Escape 或 Tab 取消按下“按鈕”
if (keycode.isEventKey(event, 'Esc') || keycode.isEventKey(event, 'Tab')) {
如果(this.buttonPressed_){
這個.unpressButton();
}
// 不要阻止 Tab 鍵的默認值 - 我們仍然想失去焦點
如果 (!keycode.isEventKey(event, 'Tab')) {
事件.preventDefault();
// 將焦點設置回菜單按鈕的按鈕
這個.menuButton_.focus();
}
}其他{
// 筆記:這是一個特殊情況,我們不會未經處理就通過
// 直到組件處理程序的按鍵事件,因為它是
// 只是結束 `MenuItem` 的按鍵處理
// 在已經向上傳遞未使用的鍵的 `Menu` 中。
}
}
/**
* 將當前的 `MenuButton` 置於按下狀態。
*/
按下按鈕() {
如果(this.enabled_){
this.buttonPressed_ = true;
這個.menu.show();
這個.menu.lockShowing();
this.menuButton_.el_.setAttribute('aria-expanded', 'true');
// 將焦點設置到子菜單中,除了在 iOS 上它會導致
// 當播放器在 iframe 中時不希望的滾動行為
如果 (IS_IOS && Dom.isInFrame()) {
// 提前返回,這樣菜單就沒有焦點
返回;
}
這個.menu.focus();
}
}
/**
* 使當前的 `MenuButton` 脫離按下狀態。
*/
unpressButton() {
如果(this.enabled_){
this.buttonPressed_ = false;
這個.menu.unlockShowing();
這個.menu.hide();
this.menuButton_.el_.setAttribute('aria-expanded', 'false');
}
}
/**
* 禁用 `MenuButton`。不要讓它被點擊。
*/
禁用(){
這個.unpressButton();
this.enabled_ = false;
this.addClass('vjs-disabled');
this.menuButton_.disable();
}
/**
* 啟用 `MenuButton`。允許它被點擊。
*/
使能夠() {
this.enabled_ = true;
this.removeClass('vjs-disabled');
this.menuButton_.enable();
}
}
Component.registerComponent('MenuButton', MenuButton);
導出默認菜單按鈕;