mirror of
https://github.com/videojs/video.js.git
synced 2025-04-11 11:42:08 +02:00
216 lines
5.5 KiB
JavaScript
216 lines
5.5 KiB
JavaScript
/* Menu
|
|
================================================================================ */
|
|
/**
|
|
* The Menu component is used to build pop up menus, including subtitle and
|
|
* captions selection menus.
|
|
*
|
|
* @param {vjs.Player|Object} player
|
|
* @param {Object=} options
|
|
* @class
|
|
* @constructor
|
|
*/
|
|
vjs.Menu = vjs.Component.extend();
|
|
|
|
/**
|
|
* Add a menu item to the menu
|
|
* @param {Object|String} component Component or component type to add
|
|
*/
|
|
vjs.Menu.prototype.addItem = function(component){
|
|
this.addChild(component);
|
|
component.on('click', vjs.bind(this, function(){
|
|
this.unlockShowing();
|
|
}));
|
|
};
|
|
|
|
/** @inheritDoc */
|
|
vjs.Menu.prototype.createEl = function(){
|
|
var contentElType = this.options().contentElType || 'ul';
|
|
this.contentEl_ = vjs.createEl(contentElType, {
|
|
className: 'vjs-menu-content'
|
|
});
|
|
var el = vjs.Component.prototype.createEl.call(this, 'div', {
|
|
append: this.contentEl_,
|
|
className: 'vjs-menu'
|
|
});
|
|
el.appendChild(this.contentEl_);
|
|
|
|
// Prevent clicks from bubbling up. Needed for Menu Buttons,
|
|
// where a click on the parent is significant
|
|
vjs.on(el, 'click', function(event){
|
|
event.preventDefault();
|
|
event.stopImmediatePropagation();
|
|
});
|
|
|
|
return el;
|
|
};
|
|
|
|
/**
|
|
* The component for a menu item. `<li>`
|
|
*
|
|
* @param {vjs.Player|Object} player
|
|
* @param {Object=} options
|
|
* @class
|
|
* @constructor
|
|
*/
|
|
vjs.MenuItem = vjs.Button.extend({
|
|
/** @constructor */
|
|
init: function(player, options){
|
|
vjs.Button.call(this, player, options);
|
|
this.selected(options['selected']);
|
|
}
|
|
});
|
|
|
|
/** @inheritDoc */
|
|
vjs.MenuItem.prototype.createEl = function(type, props){
|
|
return vjs.Button.prototype.createEl.call(this, 'li', vjs.obj.merge({
|
|
className: 'vjs-menu-item',
|
|
innerHTML: this.options_['label']
|
|
}, props));
|
|
};
|
|
|
|
/**
|
|
* Handle a click on the menu item, and set it to selected
|
|
*/
|
|
vjs.MenuItem.prototype.onClick = function(){
|
|
this.selected(true);
|
|
};
|
|
|
|
/**
|
|
* Set this menu item as selected or not
|
|
* @param {Boolean} selected
|
|
*/
|
|
vjs.MenuItem.prototype.selected = function(selected){
|
|
if (selected) {
|
|
this.addClass('vjs-selected');
|
|
this.el_.setAttribute('aria-selected',true);
|
|
} else {
|
|
this.removeClass('vjs-selected');
|
|
this.el_.setAttribute('aria-selected',false);
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* A button class with a popup menu
|
|
* @param {vjs.Player|Object} player
|
|
* @param {Object=} options
|
|
* @constructor
|
|
*/
|
|
vjs.MenuButton = vjs.Button.extend({
|
|
/** @constructor */
|
|
init: function(player, options){
|
|
vjs.Button.call(this, player, options);
|
|
|
|
this.menu = this.createMenu();
|
|
|
|
// Add list to element
|
|
this.addChild(this.menu);
|
|
|
|
// Automatically hide empty menu buttons
|
|
if (this.items && this.items.length === 0) {
|
|
this.hide();
|
|
}
|
|
|
|
this.on('keyup', this.onKeyPress);
|
|
this.el_.setAttribute('aria-haspopup', true);
|
|
this.el_.setAttribute('role', 'button');
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Track the state of the menu button
|
|
* @type {Boolean}
|
|
* @private
|
|
*/
|
|
vjs.MenuButton.prototype.buttonPressed_ = false;
|
|
|
|
vjs.MenuButton.prototype.createMenu = function(){
|
|
var menu = new vjs.Menu(this.player_);
|
|
|
|
// Add a title list item to the top
|
|
if (this.options().title) {
|
|
menu.contentEl().appendChild(vjs.createEl('li', {
|
|
className: 'vjs-menu-title',
|
|
innerHTML: vjs.capitalize(this.options().title),
|
|
tabindex: -1
|
|
}));
|
|
}
|
|
|
|
this.items = this['createItems']();
|
|
|
|
if (this.items) {
|
|
// Add menu items to the menu
|
|
for (var i = 0; i < this.items.length; i++) {
|
|
menu.addItem(this.items[i]);
|
|
}
|
|
}
|
|
|
|
return menu;
|
|
};
|
|
|
|
/**
|
|
* Create the list of menu items. Specific to each subclass.
|
|
*/
|
|
vjs.MenuButton.prototype.createItems = function(){};
|
|
|
|
/** @inheritDoc */
|
|
vjs.MenuButton.prototype.buildCSSClass = function(){
|
|
return this.className + ' vjs-menu-button ' + vjs.Button.prototype.buildCSSClass.call(this);
|
|
};
|
|
|
|
// Focus - Add keyboard functionality to element
|
|
// This function is not needed anymore. Instead, the keyboard functionality is handled by
|
|
// treating the button as triggering a submenu. When the button is pressed, the submenu
|
|
// appears. Pressing the button again makes the submenu disappear.
|
|
vjs.MenuButton.prototype.onFocus = function(){};
|
|
// Can't turn off list display that we turned on with focus, because list would go away.
|
|
vjs.MenuButton.prototype.onBlur = function(){};
|
|
|
|
vjs.MenuButton.prototype.onClick = function(){
|
|
// When you click the button it adds focus, which will show the menu indefinitely.
|
|
// So we'll remove focus when the mouse leaves the button.
|
|
// Focus is needed for tab navigation.
|
|
this.one('mouseout', vjs.bind(this, function(){
|
|
this.menu.unlockShowing();
|
|
this.el_.blur();
|
|
}));
|
|
if (this.buttonPressed_){
|
|
this.unpressButton();
|
|
} else {
|
|
this.pressButton();
|
|
}
|
|
};
|
|
|
|
vjs.MenuButton.prototype.onKeyPress = function(event){
|
|
event.preventDefault();
|
|
|
|
// Check for space bar (32) or enter (13) keys
|
|
if (event.which == 32 || event.which == 13) {
|
|
if (this.buttonPressed_){
|
|
this.unpressButton();
|
|
} else {
|
|
this.pressButton();
|
|
}
|
|
// Check for escape (27) key
|
|
} else if (event.which == 27){
|
|
if (this.buttonPressed_){
|
|
this.unpressButton();
|
|
}
|
|
}
|
|
};
|
|
|
|
vjs.MenuButton.prototype.pressButton = function(){
|
|
this.buttonPressed_ = true;
|
|
this.menu.lockShowing();
|
|
this.el_.setAttribute('aria-pressed', true);
|
|
if (this.items && this.items.length > 0) {
|
|
this.items[0].el().focus(); // set the focus to the title of the submenu
|
|
}
|
|
};
|
|
|
|
vjs.MenuButton.prototype.unpressButton = function(){
|
|
this.buttonPressed_ = false;
|
|
this.menu.unlockShowing();
|
|
this.el_.setAttribute('aria-pressed', false);
|
|
};
|