bitmovin-player-ui
Version:
Bitmovin Player UI Framework
163 lines (143 loc) • 5.6 kB
text/typescript
import { Container, ContainerConfig } from '../Container';
import { Component, ComponentConfig } from '../Component';
import { Event, EventDispatcher, NoArgs } from '../../EventDispatcher';
import { Label, LabelConfig, LabelStyle } from '../labels/Label';
import { UIInstanceManager } from '../../UIManager';
import { SelectBox } from './SelectBox';
import { VideoQualitySelectBox } from './VideoQualitySelectBox';
import { AudioQualitySelectBox } from './AudioQualitySelectBox';
import { PlaybackSpeedSelectBox } from './PlaybackSpeedSelectBox';
import { PlayerAPI } from 'bitmovin-player';
import { LocalizableText } from '../../localization/i18n';
import { ListSelector } from '../lists/ListSelector';
/**
* Configuration interface for a {@link SettingsPanelItem}
*
* @category Configs
*/
export interface SettingsPanelItemConfig extends ContainerConfig {
/**
* The label component or the text for the label.
*/
label?: LocalizableText | Component<ComponentConfig>;
/**
* The style of the label in case config.label is not a component already.
* Default: {@link LabelStyle.Text}
*/
labelStyle?: LabelStyle;
/**
* The component that configures a setting.
*/
settingComponent?: Component<ComponentConfig>;
/**
* If the setting should be added as a component to this item.
*/
addSettingAsComponent?: boolean;
/**
* Indicates if the SettingsPanelItem is representing an actual setting or if it just a label. E.g. when used
* as a title.
*/
isSetting?: boolean;
}
/**
* An item for a {@link SettingsPanelPage},
* Containing an optional {@link Label} and a component that configures a setting.
* If the components is a {@link SelectBox} it will handle the logic of displaying it or not
*
* @category Components
*/
export class SettingsPanelItem<Config extends SettingsPanelItemConfig> extends Container<Config> {
private label: Component<ComponentConfig>;
protected settingComponent: Component<ComponentConfig> | null;
private settingsPanelItemEvents = {
onActiveChanged: new EventDispatcher<SettingsPanelItem<Config>, NoArgs>(),
};
constructor(config: SettingsPanelItemConfig);
constructor(config: Config) {
super(config);
this.settingComponent = config.settingComponent;
this.config = this.mergeConfig(
config,
{
cssClass: 'ui-settings-panel-item',
role: 'menuitem',
addSettingAsComponent: true,
isSetting: true,
labelStyle: LabelStyle.Text,
} as Config,
this.config,
);
const label = config.label;
if (label !== null) {
if (label instanceof Component) {
this.label = label;
} else {
this.label = new Label({ text: label, labelStyle: config.labelStyle } as LabelConfig);
}
this.addComponent(this.label);
}
}
configure(player: PlayerAPI, uimanager: UIInstanceManager): void {
super.configure(player, uimanager);
if (this.settingComponent != null && this.config.addSettingAsComponent) {
this.addComponent(this.settingComponent);
this.updateComponents();
}
if (this.settingComponent instanceof ListSelector) {
const handleConfigItemChanged = () => {
if (!(this.settingComponent instanceof ListSelector)) {
return;
}
// The minimum number of items that must be available for the setting to be displayed
// By default, at least two items must be available, else a selection is not possible
let minItemsToDisplay = 2;
// Audio/video quality select boxes contain an additional 'auto' mode, which in combination with a single
// available quality also does not make sense
if (
(this.settingComponent instanceof VideoQualitySelectBox && this.settingComponent.hasAutoItem()) ||
this.settingComponent instanceof AudioQualitySelectBox
) {
minItemsToDisplay = 3;
}
if (this.settingComponent.itemCount() < minItemsToDisplay) {
// Hide the setting if no meaningful choice is available
this.hide();
} else if (
this.settingComponent instanceof PlaybackSpeedSelectBox &&
!uimanager.getConfig().playbackSpeedSelectionEnabled
) {
// Hide the PlaybackSpeedSelectBox if disabled in config
this.hide();
} else {
this.show();
}
// Visibility might have changed and therefore the active state might have changed so we fire the event
// TODO fire only when state has really changed (e.g. check if visibility has really changed)
this.onActiveChangedEvent();
this.getDomElement().attr('aria-haspopup', 'true');
};
this.settingComponent.onItemAdded.subscribe(handleConfigItemChanged);
this.settingComponent.onItemRemoved.subscribe(handleConfigItemChanged);
// Initialize hidden state
handleConfigItemChanged();
}
}
/**
* Checks if this settings panel item is active, i.e. visible and enabled and a user can interact with it.
* @returns {boolean} true if the panel is active, else false
*/
isActive(): boolean {
return this.isShown();
}
protected onActiveChangedEvent() {
this.settingsPanelItemEvents.onActiveChanged.dispatch(this);
}
/**
* Gets the event that is fired when the 'active' state of this item changes.
* @see #isActive
* @returns {Event<SettingsPanelItem, NoArgs>}
*/
get onActiveChanged(): Event<SettingsPanelItem<Config>, NoArgs> {
return this.settingsPanelItemEvents.onActiveChanged.getEvent();
}
}