UNPKG

chrome-devtools-frontend

Version:
185 lines (157 loc) 7.28 kB
// Copyright 2019 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. /* eslint-disable rulesdir/no_underscored_properties */ import * as i18n from '../i18n/i18n.js'; import * as UI from '../ui/ui.js'; import {MainView, TriggerDispatcher} from './MainView.js'; // eslint-disable-line no-unused-vars import {PlayerEvent} from './MediaModel.js'; // eslint-disable-line no-unused-vars import {PlayerPropertyKeys} from './PlayerPropertiesView.js'; export const UIStrings = { /** *@description A right-click context menu entry which when clicked causes the menu entry for that player to be removed. */ hidePlayer: 'Hide player', /** *@description A right-click context menu entry which should keep the element selected, while hiding all other entries. */ hideAllOthers: 'Hide all others', /** *@description Context menu entry which downloads the json dump when clicked */ savePlayerInfo: 'Save player info', /** *@description Side-panel entry title text for the players section. */ players: 'Players', }; const str_ = i18n.i18n.registerUIStrings('media/PlayerListView.ts', UIStrings); const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_); export interface PlayerStatus { playerTitle: string; playerID: string; exists: boolean; playing: boolean; titleEdited: boolean; } export interface PlayerStatusMapElement { playerStatus: PlayerStatus; playerTitleElement: HTMLElement|null; } export class PlayerEntryTreeElement extends UI.TreeOutline.TreeElement { titleFromUrl: boolean; _playerStatus: PlayerStatus; _displayContainer: MainView; constructor(playerStatus: PlayerStatus, displayContainer: MainView, playerID: string) { super(playerStatus.playerTitle, false); this.titleFromUrl = true; this._playerStatus = playerStatus; this._displayContainer = displayContainer; this.setLeadingIcons([UI.Icon.Icon.create('smallicon-videoplayer-playing', 'media-player')]); this.listItemElement.classList.add('player-entry-tree-element'); this.listItemElement.addEventListener('contextmenu', this._rightClickContextMenu.bind(this, playerID), false); } onselect(_selectedByUser?: boolean): boolean { this._displayContainer.renderMainPanel(this._playerStatus.playerID); return true; } _rightClickContextMenu(playerID: string, event: Event): boolean { const contextMenu = new UI.ContextMenu.ContextMenu(event); contextMenu.headerSection().appendItem(i18nString(UIStrings.hidePlayer), this._hidePlayer.bind(this, playerID)); contextMenu.headerSection().appendItem(i18nString(UIStrings.hideAllOthers), this._hideOthers.bind(this, playerID)); contextMenu.headerSection().appendItem(i18nString(UIStrings.savePlayerInfo), this._savePlayer.bind(this, playerID)); contextMenu.show(); return true; } _hidePlayer(playerID: string): void { this._displayContainer.markPlayerForDeletion(playerID); } _savePlayer(playerID: string): void { this._displayContainer.exportPlayerData(playerID); } _hideOthers(playerID: string): void { this._displayContainer.markOtherPlayersForDeletion(playerID); } } export class PlayerListView extends UI.Widget.VBox implements TriggerDispatcher { _playerStatuses: Map<string, PlayerEntryTreeElement>; _mainContainer: MainView; _sidebarTree: UI.TreeOutline.TreeOutlineInShadow; _playerList: UI.TreeOutline.TreeElement; constructor(mainContainer: MainView) { super(true); this._playerStatuses = new Map(); // Container where new panels can be added based on clicks. this._mainContainer = mainContainer; // The parent tree for storing sections this._sidebarTree = new UI.TreeOutline.TreeOutlineInShadow(); this.contentElement.appendChild(this._sidebarTree.element); this._sidebarTree.registerRequiredCSS('media/playerListView.css', {enableLegacyPatching: true}); // Players active in this tab. this._playerList = this._addListSection(i18nString(UIStrings.players)); this._playerList.listItemElement.classList.add('player-entry-header'); } deletePlayer(playerID: string): void { this._playerList.removeChild(this._playerStatuses.get(playerID) as UI.TreeOutline.TreeElement); this._playerStatuses.delete(playerID); } _addListSection(title: string): UI.TreeOutline.TreeElement { const treeElement = new UI.TreeOutline.TreeElement(title, true); treeElement.listItemElement.classList.add('storage-group-list-item'); treeElement.setCollapsible(false); treeElement.selectable = false; this._sidebarTree.appendChild(treeElement); return treeElement; } addMediaElementItem(playerID: string): void { const playerStatus = {playerTitle: playerID, playerID: playerID, exists: true, playing: false, titleEdited: false}; const playerElement = new PlayerEntryTreeElement(playerStatus, this._mainContainer, playerID); this._playerStatuses.set(playerID, playerElement); this._playerList.appendChild(playerElement); } setMediaElementPlayerTitle(playerID: string, newTitle: string, isTitleExtractedFromUrl: boolean): void { if (this._playerStatuses.has(playerID)) { const sidebarEntry = this._playerStatuses.get(playerID); if (sidebarEntry && (!isTitleExtractedFromUrl || sidebarEntry.titleFromUrl)) { sidebarEntry.title = newTitle; sidebarEntry.titleFromUrl = isTitleExtractedFromUrl; } } } setMediaElementPlayerIcon(playerID: string, iconName: string): void { if (this._playerStatuses.has(playerID)) { const sidebarEntry = this._playerStatuses.get(playerID); if (!sidebarEntry) { throw new Error('sidebarEntry is expected to not be null'); } sidebarEntry.setLeadingIcons([UI.Icon.Icon.create('smallicon-videoplayer-' + iconName, 'media-player')]); } } onProperty(playerID: string, property: Protocol.Media.PlayerProperty): void { // Sometimes the title will be an empty string, since this is provided // by the website. We don't want to swap title to an empty string. if (property.name === PlayerPropertyKeys.FrameTitle && property.value) { this.setMediaElementPlayerTitle(playerID, property.value as string, false); } // Url always has a value. if (property.name === PlayerPropertyKeys.FrameUrl) { const urlPathComponent = property.value.substring(property.value.lastIndexOf('/') + 1); this.setMediaElementPlayerTitle(playerID, urlPathComponent, true); } } onError(_playerID: string, _error: Protocol.Media.PlayerError): void { // TODO(tmathmeyer) show an error icon next to the player name } onMessage(_playerID: string, _message: Protocol.Media.PlayerMessage): void { // TODO(tmathmeyer) show a message count number next to the player name. } onEvent(playerID: string, event: PlayerEvent): void { if (event.value === 'PLAY') { this.setMediaElementPlayerIcon(playerID, 'playing'); } else if (event.value === 'PAUSE') { this.setMediaElementPlayerIcon(playerID, 'paused'); } else if (event.value === 'WEBMEDIAPLAYER_DESTROYED') { this.setMediaElementPlayerIcon(playerID, 'destroyed'); } } }