aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/assets/player/playlist
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2020-08-05 09:44:58 +0200
committerChocobozzz <chocobozzz@cpy.re>2020-08-07 08:58:29 +0200
commit4572c3d0d92f5b1b79b34dbe2c7b6557a8a5b7e4 (patch)
tree2c1aa81a536b50d6da0181aba6fce1db972f6191 /client/src/assets/player/playlist
parent5abc96fca2496f33075796db208fccc3543e0f65 (diff)
downloadPeerTube-4572c3d0d92f5b1b79b34dbe2c7b6557a8a5b7e4.tar.gz
PeerTube-4572c3d0d92f5b1b79b34dbe2c7b6557a8a5b7e4.tar.zst
PeerTube-4572c3d0d92f5b1b79b34dbe2c7b6557a8a5b7e4.zip
Handle basic playlist in embed
Diffstat (limited to 'client/src/assets/player/playlist')
-rw-r--r--client/src/assets/player/playlist/playlist-button.ts61
-rw-r--r--client/src/assets/player/playlist/playlist-menu-item.ts98
-rw-r--r--client/src/assets/player/playlist/playlist-menu.ts124
-rw-r--r--client/src/assets/player/playlist/playlist-plugin.ts35
4 files changed, 318 insertions, 0 deletions
diff --git a/client/src/assets/player/playlist/playlist-button.ts b/client/src/assets/player/playlist/playlist-button.ts
new file mode 100644
index 000000000..a7996ec60
--- /dev/null
+++ b/client/src/assets/player/playlist/playlist-button.ts
@@ -0,0 +1,61 @@
1import videojs from 'video.js'
2import { PlaylistPluginOptions } from '../peertube-videojs-typings'
3import { PlaylistMenu } from './playlist-menu'
4
5const ClickableComponent = videojs.getComponent('ClickableComponent')
6
7class PlaylistButton extends ClickableComponent {
8 private playlistInfoElement: HTMLElement
9 private wrapper: HTMLElement
10
11 constructor (player: videojs.Player, options?: PlaylistPluginOptions & { playlistMenu: PlaylistMenu }) {
12 super(player, options as any)
13 }
14
15 createEl () {
16 this.wrapper = super.createEl('div', {
17 className: 'vjs-playlist-button',
18 innerHTML: '',
19 tabIndex: -1
20 }) as HTMLElement
21
22 const icon = super.createEl('div', {
23 className: 'vjs-playlist-icon',
24 innerHTML: '',
25 tabIndex: -1
26 })
27
28 this.playlistInfoElement = super.createEl('div', {
29 className: 'vjs-playlist-info',
30 innerHTML: '',
31 tabIndex: -1
32 }) as HTMLElement
33
34 this.wrapper.appendChild(icon)
35 this.wrapper.appendChild(this.playlistInfoElement)
36
37 this.update()
38
39 return this.wrapper
40 }
41
42 update () {
43 const options = this.options_ as PlaylistPluginOptions
44
45 this.playlistInfoElement.innerHTML = options.getCurrentPosition() + '/' + options.playlist.videosLength
46 this.wrapper.title = this.player().localize('Playlist: {1}', [ options.playlist.displayName ])
47 }
48
49 handleClick () {
50 const playlistMenu = this.getPlaylistMenu()
51 playlistMenu.open()
52 }
53
54 private getPlaylistMenu () {
55 return (this.options_ as any).playlistMenu as PlaylistMenu
56 }
57}
58
59videojs.registerComponent('PlaylistButton', PlaylistButton)
60
61export { PlaylistButton }
diff --git a/client/src/assets/player/playlist/playlist-menu-item.ts b/client/src/assets/player/playlist/playlist-menu-item.ts
new file mode 100644
index 000000000..916c6338f
--- /dev/null
+++ b/client/src/assets/player/playlist/playlist-menu-item.ts
@@ -0,0 +1,98 @@
1import videojs from 'video.js'
2import { VideoPlaylistElement } from '@shared/models'
3import { PlaylistItemOptions } from '../peertube-videojs-typings'
4
5const Component = videojs.getComponent('Component')
6
7class PlaylistMenuItem extends Component {
8 private element: VideoPlaylistElement
9
10 constructor (player: videojs.Player, options?: PlaylistItemOptions) {
11 super(player, options as any)
12
13 this.emitTapEvents()
14
15 this.element = options.element
16
17 this.on([ 'click', 'tap' ], () => this.switchPlaylistItem())
18 this.on('keydown', event => this.handleKeyDown(event))
19 }
20
21 createEl () {
22 const options = this.options_ as PlaylistItemOptions
23
24 const li = super.createEl('li', {
25 className: 'vjs-playlist-menu-item',
26 innerHTML: ''
27 }) as HTMLElement
28
29 const positionBlock = super.createEl('div', {
30 className: 'item-position-block'
31 })
32
33 const position = super.createEl('div', {
34 className: 'item-position',
35 innerHTML: options.element.position
36 })
37
38 const player = super.createEl('div', {
39 className: 'item-player'
40 })
41
42 positionBlock.appendChild(position)
43 positionBlock.appendChild(player)
44
45 li.appendChild(positionBlock)
46
47 const thumbnail = super.createEl('img', {
48 src: window.location.origin + options.element.video.thumbnailPath
49 })
50
51 const infoBlock = super.createEl('div', {
52 className: 'info-block'
53 })
54
55 const title = super.createEl('div', {
56 innerHTML: options.element.video.name,
57 className: 'title'
58 })
59
60 const channel = super.createEl('div', {
61 innerHTML: options.element.video.channel.displayName,
62 className: 'channel'
63 })
64
65 infoBlock.appendChild(title)
66 infoBlock.appendChild(channel)
67
68 li.append(thumbnail)
69 li.append(infoBlock)
70
71 return li
72 }
73
74 setSelected (selected: boolean) {
75 if (selected) this.addClass('vjs-selected')
76 else this.removeClass('vjs-selected')
77 }
78
79 getElement () {
80 return this.element
81 }
82
83 private handleKeyDown (event: KeyboardEvent) {
84 if (event.code === 'Space' || event.code === 'Enter') {
85 this.switchPlaylistItem()
86 }
87 }
88
89 private switchPlaylistItem () {
90 const options = this.options_ as PlaylistItemOptions
91
92 options.onClicked()
93 }
94}
95
96Component.registerComponent('PlaylistMenuItem', PlaylistMenuItem)
97
98export { PlaylistMenuItem }
diff --git a/client/src/assets/player/playlist/playlist-menu.ts b/client/src/assets/player/playlist/playlist-menu.ts
new file mode 100644
index 000000000..7d7d9e12f
--- /dev/null
+++ b/client/src/assets/player/playlist/playlist-menu.ts
@@ -0,0 +1,124 @@
1import videojs from 'video.js'
2import { VideoPlaylistElement } from '@shared/models'
3import { PlaylistPluginOptions } from '../peertube-videojs-typings'
4import { PlaylistMenuItem } from './playlist-menu-item'
5
6const Component = videojs.getComponent('Component')
7
8class PlaylistMenu extends Component {
9 private menuItems: PlaylistMenuItem[]
10
11 constructor (player: videojs.Player, options?: PlaylistPluginOptions) {
12 super(player, options as any)
13
14 this.player().on('userinactive', () => {
15 this.close()
16 })
17
18 this.player().on('click', event => {
19 let current = event.target as HTMLElement
20
21 do {
22 if (
23 current.classList.contains('vjs-playlist-menu') ||
24 current.classList.contains('vjs-playlist-button')
25 ) {
26 return
27 }
28
29 current = current.parentElement
30 } while (current)
31
32 this.close()
33 })
34 }
35
36 createEl () {
37 this.menuItems = []
38
39 const options = this.getOptions()
40
41 const menu = super.createEl('div', {
42 className: 'vjs-playlist-menu',
43 innerHTML: '',
44 tabIndex: -1
45 })
46
47 const header = super.createEl('div', {
48 className: 'header'
49 })
50
51 const headerLeft = super.createEl('div')
52
53 const leftTitle = super.createEl('div', {
54 innerHTML: options.playlist.displayName,
55 className: 'title'
56 })
57
58 const leftSubtitle = super.createEl('div', {
59 innerHTML: this.player().localize('By {1}', [ options.playlist.videoChannel.displayName ]),
60 className: 'channel'
61 })
62
63 headerLeft.appendChild(leftTitle)
64 headerLeft.appendChild(leftSubtitle)
65
66 const tick = super.createEl('div', {
67 className: 'cross'
68 })
69 tick.addEventListener('click', () => this.close())
70
71 header.appendChild(headerLeft)
72 header.appendChild(tick)
73
74 const list = super.createEl('ol')
75
76 for (const playlistElement of options.elements) {
77 const item = new PlaylistMenuItem(this.player(), {
78 element: playlistElement,
79 onClicked: () => this.onItemClicked(playlistElement)
80 })
81
82 list.appendChild(item.el())
83
84 this.menuItems.push(item)
85 }
86
87 menu.appendChild(header)
88 menu.appendChild(list)
89
90 return menu
91 }
92
93 update () {
94 const options = this.getOptions()
95
96 this.updateSelected(options.getCurrentPosition())
97 }
98
99 open () {
100 this.player().addClass('playlist-menu-displayed')
101 }
102
103 close () {
104 this.player().removeClass('playlist-menu-displayed')
105 }
106
107 updateSelected (newPosition: number) {
108 for (const item of this.menuItems) {
109 item.setSelected(item.getElement().position === newPosition)
110 }
111 }
112
113 private getOptions () {
114 return this.options_ as PlaylistPluginOptions
115 }
116
117 private onItemClicked (element: VideoPlaylistElement) {
118 this.getOptions().onItemClicked(element)
119 }
120}
121
122Component.registerComponent('PlaylistMenu', PlaylistMenu)
123
124export { PlaylistMenu }
diff --git a/client/src/assets/player/playlist/playlist-plugin.ts b/client/src/assets/player/playlist/playlist-plugin.ts
new file mode 100644
index 000000000..b69d82e3c
--- /dev/null
+++ b/client/src/assets/player/playlist/playlist-plugin.ts
@@ -0,0 +1,35 @@
1import videojs from 'video.js'
2import { PlaylistPluginOptions } from '../peertube-videojs-typings'
3import { PlaylistButton } from './playlist-button'
4import { PlaylistMenu } from './playlist-menu'
5
6const Plugin = videojs.getPlugin('plugin')
7
8class PlaylistPlugin extends Plugin {
9 private playlistMenu: PlaylistMenu
10 private playlistButton: PlaylistButton
11 private options: PlaylistPluginOptions
12
13 constructor (player: videojs.Player, options?: PlaylistPluginOptions) {
14 super(player, options)
15
16 this.options = options
17
18 this.player.ready(() => {
19 player.addClass('vjs-playlist')
20 })
21
22 this.playlistMenu = new PlaylistMenu(player, options)
23 this.playlistButton = new PlaylistButton(player, Object.assign({}, options, { playlistMenu: this.playlistMenu }))
24
25 player.addChild(this.playlistMenu, options)
26 player.addChild(this.playlistButton, options)
27 }
28
29 updateSelected () {
30 this.playlistMenu.updateSelected(this.options.getCurrentPosition())
31 }
32}
33
34videojs.registerPlugin('playlist', PlaylistPlugin)
35export { PlaylistPlugin }