@gcorevideo/player 2.22.15 → 2.22.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/assets/clips/clips.ejs +1 -0
  2. package/assets/clips/clips.scss +23 -3
  3. package/assets/level-selector/list.ejs +9 -3
  4. package/assets/media-control/media-control.ejs +1 -9
  5. package/assets/media-control/media-control.scss +0 -25
  6. package/assets/media-control/width370.scss +4 -4
  7. package/dist/core.js +1 -1
  8. package/dist/index.css +602 -602
  9. package/dist/index.js +252 -229
  10. package/dist/player.d.ts +211 -144
  11. package/dist/plugins/index.css +1198 -1198
  12. package/dist/plugins/index.js +185 -167
  13. package/docs/api/{player.audioselector.md → player.audiotracks.md} +3 -3
  14. package/docs/api/player.contextmenu.md +2 -0
  15. package/docs/api/player.contextmenupluginsettings.md +2 -40
  16. package/docs/api/{player.contextmenupluginsettings.label.md → player.contextmenupluginsettings.options.md} +3 -3
  17. package/docs/api/player.md +78 -23
  18. package/docs/api/player.mediacontrol.md +8 -14
  19. package/docs/api/player.mediacontrolelement.md +4 -2
  20. package/docs/api/{player.contextmenupluginsettings.preventshowcontextmenu.md → player.mediacontrollayerelement.md} +5 -3
  21. package/docs/api/player.mediacontrolleftelement.md +16 -0
  22. package/docs/api/player.mediacontrolrightelement.md +16 -0
  23. package/docs/api/player.mediacontrolsettings.md +23 -0
  24. package/docs/api/{player.contextmenupluginsettings.url.md → player.menuoption.md} +10 -3
  25. package/docs/api/player.playbackrate.md +1 -1
  26. package/docs/api/player.playerconfig.md +1 -1
  27. package/docs/api/player.playerconfig.playbacktype.md +1 -1
  28. package/docs/api/{player.levelselector.events.md → player.qualitylevels.events.md} +2 -2
  29. package/docs/api/{player.levelselector.md → player.qualitylevels.md} +6 -6
  30. package/docs/api/{player.levelselectorpluginsettings.labels.md → player.qualitylevelspluginsettings.labels.md} +2 -2
  31. package/docs/api/{player.levelselectorpluginsettings.md → player.qualitylevelspluginsettings.md} +6 -6
  32. package/docs/api/{player.levelselectorpluginsettings.restrictresolution.md → player.qualitylevelspluginsettings.restrictresolution.md} +2 -2
  33. package/lib/plugins/clips/Clips.d.ts +21 -16
  34. package/lib/plugins/clips/Clips.d.ts.map +1 -1
  35. package/lib/plugins/clips/Clips.js +96 -98
  36. package/lib/plugins/clips/types.d.ts +19 -0
  37. package/lib/plugins/clips/types.d.ts.map +1 -0
  38. package/lib/plugins/clips/types.js +1 -0
  39. package/lib/plugins/clips/utils.d.ts +4 -0
  40. package/lib/plugins/clips/utils.d.ts.map +1 -0
  41. package/lib/plugins/clips/utils.js +36 -0
  42. package/lib/plugins/media-control/MediaControl.d.ts +4 -7
  43. package/lib/plugins/media-control/MediaControl.d.ts.map +1 -1
  44. package/lib/plugins/media-control/MediaControl.js +19 -31
  45. package/lib/plugins/utils.d.ts +9 -1
  46. package/lib/plugins/utils.d.ts.map +1 -1
  47. package/lib/plugins/utils.js +9 -10
  48. package/lib/plugins/vast-ads/loaderxml.js +2 -2
  49. package/lib/testUtils.d.ts.map +1 -1
  50. package/lib/testUtils.js +2 -5
  51. package/package.json +1 -1
  52. package/src/plugins/clips/Clips.ts +116 -135
  53. package/src/plugins/clips/__tests__/Clips.test.ts +72 -0
  54. package/src/plugins/clips/__tests__/__snapshots__/Clips.test.ts.snap +14 -0
  55. package/src/plugins/clips/types.ts +22 -0
  56. package/src/plugins/clips/utils.ts +54 -0
  57. package/src/plugins/level-selector/__tests__/__snapshots__/QualityLevels.test.ts.snap +18 -18
  58. package/src/plugins/media-control/MediaControl.ts +31 -58
  59. package/src/plugins/media-control/__tests__/__snapshots__/MediaControl.test.ts.snap +7 -35
  60. package/src/plugins/utils.ts +9 -7
  61. package/src/plugins/vast-ads/loaderxml.ts +2 -2
  62. package/src/testUtils.ts +2 -5
  63. package/temp/player.api.json +332 -262
  64. package/tsconfig.tsbuildinfo +1 -1
  65. package/docs/api/player.mediacontrol.handlecustomarea.md +0 -52
@@ -1,55 +1,54 @@
1
- import { Container, Events, UICorePlugin, $ } from '@clappr/core'
1
+ import { Container, Events, UICorePlugin, $, template } from '@clappr/core'
2
+ import { trace } from '@gcorevideo/utils'
3
+ import assert from 'assert'
2
4
 
3
5
  import { TimeProgress } from '../../playback.types.js'
4
6
  import type { ZeptoResult } from '../../types.js'
5
- import { strtimeToMiliseconds } from '../utils.js'
6
7
  import '../../../assets/clips/clips.scss'
7
- import assert from 'assert'
8
-
9
- type ClipDesc = {
10
- start: number
11
- text: string
12
- end: number
13
- index: number
14
- }
8
+ import { ClipDesc } from './types.js'
9
+ import { buildSvg, parseClips } from './utils.js'
10
+ import clipsHTML from '../../../assets/clips/clips.ejs'
15
11
 
16
- type ClipItem = {
17
- start: number
18
- text: string
19
- }
12
+ const T = 'plugins.clips'
20
13
 
21
14
  /**
22
- * Configuration options for the {@link ClipsPlugin | clips} plugin.
15
+ * Configuration options for the {@link ClipsPlugin} plugin.
23
16
  * @beta
24
17
  */
25
18
  export interface ClipsPluginSettings {
26
19
  /**
27
- * The text to display over the seekbar.
20
+ * The compiled text of the clips description, one clip per line in format :
21
+ * `HH:MM:SS text` or `MM:SS text` or `SS text`
28
22
  */
29
23
  text: string
30
24
  }
31
25
 
26
+ const VERSION = '2.22.16'
27
+ const CLAPPR_VERSION = '0.11.4'
28
+
32
29
  /**
33
- * `PLUGIN` that shows text over the seekbar to indicate the current clip.
30
+ * `PLUGIN` that allows marking up the timeline of the video
34
31
  * @beta
35
32
  * @remarks
33
+ * The plugin decorates the seekbar with notches to indicate the clips of the video and displays current clip text in the left panel
34
+ *
36
35
  * Depends on:
37
36
  *
38
37
  * - {@link MediaControl}
39
38
  *
40
39
  * Configuration options - {@link ClipsPluginSettings}
41
40
  */
42
- export class ClipsPlugin extends UICorePlugin {
43
- private clips: Map<number, ClipDesc> = new Map()
44
-
45
- private duration: number = 0
41
+ export class Clips extends UICorePlugin {
42
+ private barStyle: HTMLStyleElement | null = null
46
43
 
47
- private durationGetting = false
44
+ private clips: ClipDesc[] = []
48
45
 
49
- private _oldContainer: Container | undefined
46
+ private oldContainer: Container | undefined
50
47
 
51
48
  private svgMask: ZeptoResult | null = null
52
49
 
50
+ private static readonly template = template(clipsHTML)
51
+
53
52
  /**
54
53
  * @internal
55
54
  */
@@ -62,174 +61,156 @@ export class ClipsPlugin extends UICorePlugin {
62
61
  */
63
62
  override get attributes() {
64
63
  return {
65
- class: this.name,
64
+ class: 'media-control-clips',
66
65
  }
67
66
  }
68
67
 
68
+ get version() {
69
+ return VERSION
70
+ }
71
+
72
+ get supportedVersion() {
73
+ return { min: CLAPPR_VERSION }
74
+ }
75
+
69
76
  /**
70
77
  * @internal
71
78
  */
72
79
  override bindEvents() {
73
- const mediaControl = this.core.getPlugin('media_control')
74
- assert(mediaControl, 'media_control plugin is required')
75
- this.listenToOnce(this.core, Events.CORE_READY, this._onCoreReady)
76
- // TODO listen to CORE_ACTIVE_CONTAINER_CHANGED
80
+ this.listenToOnce(this.core, Events.CORE_READY, this.onCoreReady)
81
+ this.listenTo(this.core, Events.CORE_RESIZE, this.playerResize)
77
82
  this.listenTo(
78
- mediaControl,
79
- Events.MEDIACONTROL_CONTAINERCHANGED,
80
- this._onMediaControlContainerChanged,
83
+ this.core,
84
+ Events.CORE_ACTIVE_CONTAINER_CHANGED,
85
+ this.onContainerChanged,
81
86
  )
82
- this.listenTo(this.core, Events.CORE_RESIZE, this.playerResize)
83
87
  }
84
88
 
85
- private _onCoreReady() {
89
+ override render() {
90
+ trace(`${T} render`)
86
91
  if (!this.options.clips) {
87
- this.destroy()
92
+ return this
93
+ }
94
+ this.$el.html(Clips.template())
95
+ this.$el.hide()
96
+ return this
97
+ }
88
98
 
89
- return
99
+ override destroy() {
100
+ if (this.barStyle) {
101
+ this.barStyle.remove()
102
+ this.barStyle = null
90
103
  }
104
+ return super.destroy()
105
+ }
91
106
 
92
- this.parseClips()
107
+ override disable() {
108
+ if (this.barStyle) {
109
+ this.barStyle.remove()
110
+ this.barStyle = null
111
+ }
112
+ return super.disable()
93
113
  }
94
114
 
95
- private _onMediaControlContainerChanged() {
96
- this._bindContainerEvents()
115
+ override enable() {
116
+ this.render()
117
+ return super.enable()
97
118
  }
98
119
 
99
- private playerResize() {
100
- this.durationGetting = false
101
- if (this.durationGetting) {
102
- this.makeSvg(this.duration)
103
- }
120
+ private onCoreReady() {
121
+ trace(`${T} onCoreReady`)
122
+ const mediaControl = this.core.getPlugin('media_control')
123
+ assert(mediaControl, 'media_control plugin is required')
124
+
125
+ this.parseClips(this.options.clips.text)
126
+ this.listenTo(mediaControl, Events.MEDIACONTROL_RENDERED, this.onMcRender)
104
127
  }
105
128
 
106
- private _bindContainerEvents() {
107
- if (this._oldContainer) {
129
+ private onMcRender() {
130
+ trace(`${T} onMcRender`)
131
+ const mediaControl = this.core.getPlugin('media_control')
132
+ mediaControl.mount('clips', this.$el)
133
+ }
134
+
135
+ private onContainerChanged() {
136
+ trace(`${T} onContainerChanged`)
137
+ // TODO figure out the conditions of changing the container (without destroying the previous one)
138
+ if (this.oldContainer) {
108
139
  this.stopListening(
109
- this._oldContainer,
140
+ this.oldContainer,
110
141
  Events.CONTAINER_TIMEUPDATE,
111
142
  this.onTimeUpdate,
112
143
  )
113
144
  }
114
-
115
- const mediaControl = this.core.getPlugin('media_control')
116
- this._oldContainer = mediaControl.container
117
- this.durationGetting = false
145
+ this.oldContainer = this.core.activeContainer
146
+ if (this.svgMask) {
147
+ this.svgMask.remove()
148
+ this.svgMask = null
149
+ }
118
150
  this.listenTo(
119
- mediaControl.container,
151
+ this.core.activeContainer,
120
152
  Events.CONTAINER_TIMEUPDATE,
121
153
  this.onTimeUpdate,
122
154
  )
123
155
  }
124
156
 
157
+ private playerResize() {
158
+ const duration = this.core.activeContainer.getDuration()
159
+ if (duration) {
160
+ this.makeSvg(duration)
161
+ }
162
+ }
163
+
125
164
  private onTimeUpdate(event: TimeProgress) {
126
- if (!this.durationGetting) {
127
- this.duration = event.total
165
+ if (!this.svgMask) {
128
166
  this.makeSvg(event.total)
129
- this.durationGetting = true
130
167
  }
131
-
132
- for (const value of this.clips.values()) {
133
- if (event.current >= value.start && event.current < value.end) {
168
+ for (const value of this.clips) {
169
+ if (
170
+ (event.current >= value.start && !value.end) ||
171
+ event.current < value.end
172
+ ) {
134
173
  this.setClipText(value.text)
135
174
  break
136
175
  }
137
176
  }
138
177
  }
139
178
 
140
- private parseClips() {
141
- const textArr = this.options.clips.text.split('\n')
142
-
143
- const clipsArr = textArr
144
- .map((val: string) => {
145
- const matchRes = val.match(/(\d+:\d+|:\d+) (.+)/i)
146
-
147
- return matchRes
148
- ? {
149
- start: strtimeToMiliseconds(matchRes[1]),
150
- text: matchRes[2],
151
- }
152
- : null
153
- })
154
- .filter((clip: ClipItem | null) => clip !== null)
155
-
156
- clipsArr.sort((a: ClipDesc, b: ClipDesc) => a.start - b.start)
157
-
158
- clipsArr.forEach((clip: ClipDesc, index: number) => {
159
- this.clips.set(clip.start, {
160
- index,
161
- start: clip.start,
162
- text: clip.text,
163
- end: clipsArr[index + 1] ? clipsArr[index + 1].start : null,
164
- })
165
- })
166
- }
167
-
168
- /**
169
- * Returns the text of the current clip.
170
- * @param time - The current time of the player.
171
- * @returns The text of the current clip.
172
- */
173
- getText(time: number) {
174
- for (const [key, value] of this.clips.entries()) {
175
- if (time >= value.start && time < value.end) {
176
- return value.text
177
- }
178
- }
179
- return ''
179
+ private parseClips(text: string) {
180
+ this.clips = parseClips(text)
180
181
  }
181
182
 
182
183
  private makeSvg(duration: number) {
183
- let svg =
184
- '<svg width="0" height="0">\n' + '<defs>\n' + '<clipPath id="myClip">\n'
185
- const widthOfSeek = this.core.activeContainer.$el.width()
186
- let finishValue = 0
187
-
188
- this.clips.forEach((val) => {
189
- let end = val.end
190
-
191
- if (!end) {
192
- end = val.end = duration
193
- }
194
-
195
- const widthChunk = ((end - val.start) * widthOfSeek) / duration
196
-
197
- svg += `<rect x="${finishValue}" y="0" width="${
198
- widthChunk - 2
199
- }" height="30"/>\n`
200
- finishValue += widthChunk
201
- })
202
-
203
- svg += `<rect x="${finishValue}" y="0" width="${
204
- widthOfSeek - finishValue
205
- }" height="30"/>\n`
206
- svg += '</clipPath>' + '</defs>' + '</svg>'
184
+ const svg = buildSvg(
185
+ this.clips,
186
+ duration,
187
+ this.core.activeContainer.$el.width(),
188
+ )
207
189
  this.setSVGMask(svg)
208
190
  }
209
191
 
210
192
  private setSVGMask(svg: string) {
211
- // this.core.mediaControl.setSVGMask(svg);
212
193
  if (this.svgMask) {
213
194
  this.svgMask.remove()
214
195
  }
215
196
 
216
- const mediaControl = this.core.getPlugin('media_control')
217
- const $seekBarContainer =
218
- mediaControl.getElement('seekBarContainer')
219
- if ($seekBarContainer?.get(0)) {
220
- $seekBarContainer.addClass('clips')
221
- }
222
-
223
197
  this.svgMask = $(svg)
224
- $seekBarContainer?.append(this.svgMask)
198
+ this.$el.append(this.svgMask)
199
+ if (!this.barStyle) {
200
+ this.barStyle = document.createElement('style')
201
+ this.barStyle.textContent = `
202
+ .bar-container[data-seekbar] {
203
+ clip-path: url("#myClip");
204
+ }`
205
+ this.$el.append(this.barStyle)
206
+ }
225
207
  }
226
208
 
227
209
  private setClipText(text: string) {
228
- const mediaControl = this.core.getPlugin('media_control')
229
- const $clipText = mediaControl.getElement('clipText')
230
- if ($clipText && text) {
231
- $clipText.show()
232
- $clipText.text(`${text}`)
210
+ if (text) {
211
+ this.$el.show().find('#clips-text').text(text)
212
+ } else {
213
+ this.$el.hide()
233
214
  }
234
215
  }
235
216
  }
@@ -0,0 +1,72 @@
1
+ import { beforeEach, describe, expect, it, vi } from 'vitest'
2
+ import { Clips } from '../Clips'
3
+ import { createMockCore, createMockMediaControl } from '../../../testUtils'
4
+ import { Events } from '@clappr/core'
5
+
6
+ // import { LogTracer, Logger, setTracer } from '@gcorevideo/utils'
7
+
8
+ // Logger.enable('*')
9
+ // setTracer(new LogTracer('Clips.text'))
10
+
11
+ describe('ClipsPlugin', () => {
12
+ let core: any
13
+ let mediaControl: any
14
+ let clips: Clips
15
+ beforeEach(() => {
16
+ core = createMockCore({
17
+ clips: {
18
+ text: `
19
+ 00:00:00 Introduction
20
+ 00:05:00 Main part
21
+ 00:15:00 Conclusion
22
+ `,
23
+ },
24
+ })
25
+ mediaControl = createMockMediaControl(core)
26
+ core.getPlugin.mockImplementation((name: string) => {
27
+ if (name === 'media_control') return mediaControl
28
+ return null
29
+ })
30
+ clips = new Clips(core)
31
+ core.emit(Events.CORE_READY)
32
+ core.emit(Events.CORE_ACTIVE_CONTAINER_CHANGED, core.activeContainer)
33
+ vi.spyOn(core.activeContainer.$el, 'width').mockReturnValue(600)
34
+ core.activeContainer.emit(Events.CONTAINER_TIMEUPDATE, {
35
+ current: 0,
36
+ total: 1200,
37
+ })
38
+ })
39
+ it('should render indicator', () => {
40
+ expect(clips.el.innerHTML).toMatchSnapshot()
41
+ })
42
+ it('should render notches on the seek bar', () => {
43
+ const svg = clips.$el.find('svg')
44
+ expect(svg).toBeDefined()
45
+ expect(svg?.find('rect').length).toBe(3)
46
+ })
47
+ describe('as time progresses', () => {
48
+ describe.each([
49
+ [60, 'Introduction'],
50
+ [310, 'Main part'],
51
+ [1001, 'Conclusion'],
52
+ ])('@%s', (time, expected) => {
53
+ beforeEach(() => {
54
+ core.activeContainer.emit(Events.CONTAINER_TIMEUPDATE, {
55
+ current: time,
56
+ total: 1200,
57
+ })
58
+ })
59
+ it(`text should be "${expected}"`, () => {
60
+ expect(clips.$el.find('#clips-text').text()).toBe(expected)
61
+ })
62
+ })
63
+ })
64
+ describe('when media control is rendered', () => {
65
+ beforeEach(() => {
66
+ mediaControl.trigger(Events.MEDIACONTROL_RENDERED)
67
+ })
68
+ it('should mount the indicator', () => {
69
+ expect(mediaControl.mount).toHaveBeenCalledWith('clips', clips.$el)
70
+ })
71
+ })
72
+ })
@@ -0,0 +1,14 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`ClipsPlugin > should render indicator 1`] = `
4
+ "<div class="media-clip-text" id="clips-text">Introduction</div><svg width="0" height="0">
5
+ <defs>
6
+ <clipPath id="myClip">
7
+ <rect x="0" y="0" width="148" height="30"></rect>
8
+ <rect x="150" y="0" width="298" height="30"></rect>
9
+ <rect x="450" y="0" width="148" height="30"></rect>
10
+ </clipPath></defs></svg><style>
11
+ .bar-container[data-seekbar] {
12
+ clip-path: url("#myClip");
13
+ }</style>"
14
+ `;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Clip description.
3
+ * @beta
4
+ */
5
+ export type ClipDesc = {
6
+ /**
7
+ * Start time of the clip in the video timeline, s.
8
+ */
9
+ start: number
10
+ /**
11
+ * Text to display over the seekbar.
12
+ */
13
+ text: string
14
+ /**
15
+ * End time of the clip (start time of the next clip).
16
+ */
17
+ end: number
18
+ /**
19
+ * Index of the clip.
20
+ */
21
+ // index: number
22
+ }
@@ -0,0 +1,54 @@
1
+ import { ClipDesc } from './types.js'
2
+ import { parseClipTime } from '../utils.js'
3
+
4
+ type ClipItem = {
5
+ start: number
6
+ text: string
7
+ }
8
+
9
+ export function parseClips(text: string): ClipDesc[] {
10
+ const clipsArr = text
11
+ .split('\n')
12
+ .map((val: string) => {
13
+ const matchRes = val.match(/(((\d+:)?\d+:)?\d+) (.+)/i)
14
+ return matchRes
15
+ ? {
16
+ start: parseClipTime(matchRes[1]),
17
+ text: matchRes[4],
18
+ }
19
+ : null
20
+ })
21
+ .filter((clip: ClipItem | null) => clip !== null)
22
+ .sort((a: ClipItem, b: ClipItem) => a.start - b.start)
23
+ return clipsArr.map((clip: ClipItem, index: number) => ({
24
+ start: clip.start,
25
+ text: clip.text,
26
+ end: index < clipsArr.length - 1 ? clipsArr[index + 1].start : 0,
27
+ }))
28
+ }
29
+
30
+ export function buildSvg(clips: ClipDesc[], duration: number, barWidth: number): string {
31
+ let svg =
32
+ '<svg width="0" height="0">\n' + '<defs>\n' + '<clipPath id="myClip">\n'
33
+ let rightEdge = 0
34
+
35
+ clips.forEach((val) => {
36
+ const end = val.end || duration
37
+
38
+ const chunkWidth = Math.round(((end - val.start) * barWidth) / duration)
39
+
40
+ svg += `<rect x="${rightEdge}" y="0" width="${
41
+ chunkWidth - 2
42
+ }" height="30"/>\n`
43
+ rightEdge += chunkWidth
44
+ })
45
+
46
+ if (rightEdge < barWidth) {
47
+ svg += `<rect x="${rightEdge}" y="0" width="${
48
+ barWidth - rightEdge
49
+ }" height="30"/>\n`
50
+ }
51
+ svg += '</clipPath>' + '</defs>' + '</svg>'
52
+
53
+ return svg
54
+ }
@@ -8,7 +8,7 @@ exports[`QualityLevels > basically > auto > should render the selected level 1`]
8
8
  <ul class="gear-sub-menu quality-levels" id="level-selector-menu" role="menu">
9
9
 
10
10
  <li class="current">
11
- <a href="#" class="gear-sub-menu_btn gcore-skin-text-color gcore-skin-active" data-id="-1" id="level_selector_auto">
11
+ <a href="#" class="gear-sub-menu_btn gcore-skin-text-color gcore-skin-active" data-id="-1" id="level_selector_auto" aria-checked="true" role="menuitemradio">
12
12
  <span class="check-icon">/assets/icons/new/check.svg</span>
13
13
  auto
14
14
  </a>
@@ -16,21 +16,21 @@ exports[`QualityLevels > basically > auto > should render the selected level 1`]
16
16
 
17
17
 
18
18
  <li class="">
19
- <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="2" data-disabled="false" data-checked="false" role="menuitemradio" id="level_selector_1080">
19
+ <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="2" aria-disabled="false" aria-checked="false" role="menuitemradio" id="level_selector_1080">
20
20
  <span class="check-icon">/assets/icons/new/check.svg</span>
21
21
  Full HD
22
22
  </a>
23
23
  </li>
24
24
 
25
25
  <li class="">
26
- <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="1" data-disabled="false" data-checked="false" role="menuitemradio" id="level_selector_720">
26
+ <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="1" aria-disabled="false" aria-checked="false" role="menuitemradio" id="level_selector_720">
27
27
  <span class="check-icon">/assets/icons/new/check.svg</span>
28
28
  HD
29
29
  </a>
30
30
  </li>
31
31
 
32
32
  <li class="">
33
- <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="0" data-disabled="false" data-checked="false" role="menuitemradio" id="level_selector_360">
33
+ <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="0" aria-disabled="false" aria-checked="false" role="menuitemradio" id="level_selector_360">
34
34
  <span class="check-icon">/assets/icons/new/check.svg</span>
35
35
  360p
36
36
  </a>
@@ -48,7 +48,7 @@ exports[`QualityLevels > basically > custom label > should render the selected l
48
48
  <ul class="gear-sub-menu quality-levels" id="level-selector-menu" role="menu">
49
49
 
50
50
  <li class="">
51
- <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="-1" id="level_selector_auto">
51
+ <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="-1" id="level_selector_auto" aria-checked="true" role="menuitemradio">
52
52
  <span class="check-icon">/assets/icons/new/check.svg</span>
53
53
  auto
54
54
  </a>
@@ -56,21 +56,21 @@ exports[`QualityLevels > basically > custom label > should render the selected l
56
56
 
57
57
 
58
58
  <li class="">
59
- <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="2" data-disabled="false" data-checked="false" role="menuitemradio" id="level_selector_1080">
59
+ <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="2" aria-disabled="false" aria-checked="false" role="menuitemradio" id="level_selector_1080">
60
60
  <span class="check-icon">/assets/icons/new/check.svg</span>
61
61
  Full HD
62
62
  </a>
63
63
  </li>
64
64
 
65
65
  <li class="current">
66
- <a href="#" class="gear-sub-menu_btn gcore-skin-text-color gcore-skin-active" data-id="1" data-disabled="false" data-checked="false" role="menuitemradio" id="level_selector_720">
66
+ <a href="#" class="gear-sub-menu_btn gcore-skin-text-color gcore-skin-active" data-id="1" aria-disabled="false" aria-checked="false" role="menuitemradio" id="level_selector_720">
67
67
  <span class="check-icon">/assets/icons/new/check.svg</span>
68
68
  HD
69
69
  </a>
70
70
  </li>
71
71
 
72
72
  <li class="">
73
- <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="0" data-disabled="false" data-checked="false" role="menuitemradio" id="level_selector_360">
73
+ <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="0" aria-disabled="false" aria-checked="false" role="menuitemradio" id="level_selector_360">
74
74
  <span class="check-icon">/assets/icons/new/check.svg</span>
75
75
  360p
76
76
  </a>
@@ -88,7 +88,7 @@ exports[`QualityLevels > basically > standard label > should render the selected
88
88
  <ul class="gear-sub-menu quality-levels" id="level-selector-menu" role="menu">
89
89
 
90
90
  <li class="">
91
- <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="-1" id="level_selector_auto">
91
+ <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="-1" id="level_selector_auto" aria-checked="true" role="menuitemradio">
92
92
  <span class="check-icon">/assets/icons/new/check.svg</span>
93
93
  auto
94
94
  </a>
@@ -96,21 +96,21 @@ exports[`QualityLevels > basically > standard label > should render the selected
96
96
 
97
97
 
98
98
  <li class="">
99
- <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="2" data-disabled="false" data-checked="false" role="menuitemradio" id="level_selector_1080">
99
+ <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="2" aria-disabled="false" aria-checked="false" role="menuitemradio" id="level_selector_1080">
100
100
  <span class="check-icon">/assets/icons/new/check.svg</span>
101
101
  Full HD
102
102
  </a>
103
103
  </li>
104
104
 
105
105
  <li class="">
106
- <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="1" data-disabled="false" data-checked="false" role="menuitemradio" id="level_selector_720">
106
+ <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="1" aria-disabled="false" aria-checked="false" role="menuitemradio" id="level_selector_720">
107
107
  <span class="check-icon">/assets/icons/new/check.svg</span>
108
108
  HD
109
109
  </a>
110
110
  </li>
111
111
 
112
112
  <li class="current">
113
- <a href="#" class="gear-sub-menu_btn gcore-skin-text-color gcore-skin-active" data-id="0" data-disabled="false" data-checked="false" role="menuitemradio" id="level_selector_360">
113
+ <a href="#" class="gear-sub-menu_btn gcore-skin-text-color gcore-skin-active" data-id="0" aria-disabled="false" aria-checked="false" role="menuitemradio" id="level_selector_360">
114
114
  <span class="check-icon">/assets/icons/new/check.svg</span>
115
115
  360p
116
116
  </a>
@@ -129,21 +129,21 @@ exports[`QualityLevels > options.restrictResolution > given vertical video forma
129
129
 
130
130
 
131
131
  <li class=" disabled">
132
- <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="2" data-disabled="true" data-checked="false" role="menuitemradio" id="level_selector_1080">
132
+ <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="2" aria-disabled="true" aria-checked="false" role="menuitemradio" id="level_selector_1080">
133
133
  <span class="check-icon">/assets/icons/new/check.svg</span>
134
134
  1080p
135
135
  </a>
136
136
  </li>
137
137
 
138
138
  <li class=" disabled">
139
- <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="1" data-disabled="true" data-checked="false" role="menuitemradio" id="level_selector_720">
139
+ <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="1" aria-disabled="true" aria-checked="false" role="menuitemradio" id="level_selector_720">
140
140
  <span class="check-icon">/assets/icons/new/check.svg</span>
141
141
  720p
142
142
  </a>
143
143
  </li>
144
144
 
145
145
  <li class=" current">
146
- <a href="#" class="gear-sub-menu_btn gcore-skin-text-color gcore-skin-active" data-id="0" data-disabled="false" data-checked="true" role="menuitemradio" id="level_selector_360">
146
+ <a href="#" class="gear-sub-menu_btn gcore-skin-text-color gcore-skin-active" data-id="0" aria-disabled="false" aria-checked="true" role="menuitemradio" id="level_selector_360">
147
147
  <span class="check-icon">/assets/icons/new/check.svg</span>
148
148
  360p
149
149
  </a>
@@ -172,21 +172,21 @@ exports[`QualityLevels > options.restrictResolution > initially > when opened >
172
172
 
173
173
 
174
174
  <li class=" disabled">
175
- <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="2" data-disabled="true" data-checked="false" role="menuitemradio" id="level_selector_1080">
175
+ <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="2" aria-disabled="true" aria-checked="false" role="menuitemradio" id="level_selector_1080">
176
176
  <span class="check-icon">/assets/icons/new/check.svg</span>
177
177
  1080p
178
178
  </a>
179
179
  </li>
180
180
 
181
181
  <li class=" disabled">
182
- <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="1" data-disabled="true" data-checked="false" role="menuitemradio" id="level_selector_720">
182
+ <a href="#" class="gear-sub-menu_btn gcore-skin-text-color" data-id="1" aria-disabled="true" aria-checked="false" role="menuitemradio" id="level_selector_720">
183
183
  <span class="check-icon">/assets/icons/new/check.svg</span>
184
184
  720p
185
185
  </a>
186
186
  </li>
187
187
 
188
188
  <li class=" current">
189
- <a href="#" class="gear-sub-menu_btn gcore-skin-text-color gcore-skin-active" data-id="0" data-disabled="false" data-checked="true" role="menuitemradio" id="level_selector_360">
189
+ <a href="#" class="gear-sub-menu_btn gcore-skin-text-color gcore-skin-active" data-id="0" aria-disabled="false" aria-checked="true" role="menuitemradio" id="level_selector_360">
190
190
  <span class="check-icon">/assets/icons/new/check.svg</span>
191
191
  360p
192
192
  </a>