From 56674bb9f81775ff85115e7daa7d9be0db95c001 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 5 Aug 2020 11:41:22 +0200 Subject: [PATCH] Handle unavailable videos in embed playlists --- .../player/playlist/playlist-menu-item.ts | 45 ++++++++++++++----- .../assets/player/playlist/playlist-menu.ts | 14 +++++- client/src/sass/player/playlist.scss | 35 ++++++++++----- scripts/i18n/create-custom-files.ts | 3 +- 4 files changed, 71 insertions(+), 26 deletions(-) diff --git a/client/src/assets/player/playlist/playlist-menu-item.ts b/client/src/assets/player/playlist/playlist-menu-item.ts index 916c6338f..21a7f8046 100644 --- a/client/src/assets/player/playlist/playlist-menu-item.ts +++ b/client/src/assets/player/playlist/playlist-menu-item.ts @@ -26,24 +26,47 @@ class PlaylistMenuItem extends Component { innerHTML: '' }) as HTMLElement + if (!options.element.video) { + li.classList.add('vjs-disabled') + } + const positionBlock = super.createEl('div', { className: 'item-position-block' - }) + }) as HTMLElement const position = super.createEl('div', { className: 'item-position', innerHTML: options.element.position }) + positionBlock.appendChild(position) + li.appendChild(positionBlock) + + if (options.element.video) { + this.buildAvailableVideo(li, positionBlock, options) + } else { + this.buildUnavailableVideo(li) + } + + return li + } + + setSelected (selected: boolean) { + if (selected) this.addClass('vjs-selected') + else this.removeClass('vjs-selected') + } + + getElement () { + return this.element + } + + private buildAvailableVideo (li: HTMLElement, positionBlock: HTMLElement, options: PlaylistItemOptions) { const player = super.createEl('div', { className: 'item-player' }) - positionBlock.appendChild(position) positionBlock.appendChild(player) - li.appendChild(positionBlock) - const thumbnail = super.createEl('img', { src: window.location.origin + options.element.video.thumbnailPath }) @@ -67,17 +90,15 @@ class PlaylistMenuItem extends Component { li.append(thumbnail) li.append(infoBlock) - - return li } - setSelected (selected: boolean) { - if (selected) this.addClass('vjs-selected') - else this.removeClass('vjs-selected') - } + private buildUnavailableVideo (li: HTMLElement) { + const block = super.createEl('div', { + className: 'item-unavailable', + innerHTML: this.player().localize('Unavailable video') + }) - getElement () { - return this.element + li.appendChild(block) } private handleKeyDown (event: KeyboardEvent) { diff --git a/client/src/assets/player/playlist/playlist-menu.ts b/client/src/assets/player/playlist/playlist-menu.ts index 7d7d9e12f..37284fb44 100644 --- a/client/src/assets/player/playlist/playlist-menu.ts +++ b/client/src/assets/player/playlist/playlist-menu.ts @@ -11,8 +11,18 @@ class PlaylistMenu extends Component { constructor (player: videojs.Player, options?: PlaylistPluginOptions) { super(player, options as any) - this.player().on('userinactive', () => { - this.close() + const self = this + + function userInactiveHandler () { + self.close() + } + + this.el().addEventListener('mouseenter', () => { + this.player().off('userinactive', userInactiveHandler) + }) + + this.el().addEventListener('mouseleave', () => { + this.player().one('userinactive', userInactiveHandler) }) this.player().on('click', event => { diff --git a/client/src/sass/player/playlist.scss b/client/src/sass/player/playlist.scss index c242acba8..544d45a48 100644 --- a/client/src/sass/player/playlist.scss +++ b/client/src/sass/player/playlist.scss @@ -24,17 +24,17 @@ $playlist-menu-width: 350px; justify-content: space-between; .title { + @include ellipsis; + font-size: 14px; margin-bottom: 5px; - white-space: nowrap; - text-overflow: ellipsis; } .channel { + @include ellipsis; + font-size: 11px; color: #bfbfbf; - white-space: nowrap; - text-overflow: ellipsis; } .cross { @@ -106,9 +106,13 @@ $playlist-menu-width: 350px; } .vjs-playlist-menu-item { - cursor: pointer; display: flex; padding: 10px 0; + height: 60px; + + &:not(.vjs-disabled) { + cursor: pointer; + } .item-position-block { position: relative; @@ -116,6 +120,14 @@ $playlist-menu-width: 350px; align-items: center; justify-content: center; width: 30px; + flex-shrink: 0; + } + + .item-unavailable { + position: relative; + display: flex; + align-items: center; + justify-content: center; } .item-player { @@ -136,7 +148,7 @@ $playlist-menu-width: 350px; } } - &:hover { + &:hover:not(.vjs-disabled) { background-color: rgba(150, 150, 150, 0.2); } @@ -146,20 +158,21 @@ $playlist-menu-width: 350px; } .info-block { - margin-left: 10px; + margin: 0 10px; + min-width: 1px; .title { + @include ellipsis; + font-size: 13px; margin-bottom: 5px; - white-space: nowrap; - text-overflow: ellipsis; } .channel { + @include ellipsis; + font-size: 11px; color: #bfbfbf; - white-space: nowrap; - text-overflow: ellipsis; } } } diff --git a/scripts/i18n/create-custom-files.ts b/scripts/i18n/create-custom-files.ts index 89a967b14..78a51d1e6 100755 --- a/scripts/i18n/create-custom-files.ts +++ b/scripts/i18n/create-custom-files.ts @@ -52,7 +52,8 @@ values(VIDEO_CATEGORIES) 'This playlist does not exist', 'We cannot fetch the playlist. Please try again later.', 'Playlist: {1}', - 'By {1}' + 'By {1}', + 'Unavailable video' ]) .forEach(v => { serverKeys[v] = v })