@financial-times/cp-content-pipeline-ui 6.15.2 → 6.15.3
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.
- package/CHANGELOG.md +7 -0
- package/lib/components/Clip/client/index.js +34 -15
- package/lib/components/Clip/client/index.js.map +1 -1
- package/lib/components/Clip/test/fixtures.d.ts +1 -0
- package/lib/components/Clip/test/fixtures.js +20 -1
- package/lib/components/Clip/test/fixtures.js.map +1 -1
- package/lib/components/Clip/test/index.spec.js +41 -29
- package/lib/components/Clip/test/index.spec.js.map +1 -1
- package/package.json +1 -1
- package/src/components/Clip/client/index.ts +41 -18
- package/src/components/Clip/test/fixtures.ts +21 -0
- package/src/components/Clip/test/index.spec.ts +50 -35
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -458,6 +458,7 @@ class Clip extends ClipInterface {
|
|
|
458
458
|
// disable default controls
|
|
459
459
|
video.controls = false
|
|
460
460
|
|
|
461
|
+
// CREATE ALL THE CUSTOM CONTOLS
|
|
461
462
|
const customControls = document.createElement('div')
|
|
462
463
|
customControls.classList.add('cp-clip__video-controls')
|
|
463
464
|
|
|
@@ -600,12 +601,7 @@ class Clip extends ClipInterface {
|
|
|
600
601
|
customControls.prepend(playIconContainer)
|
|
601
602
|
customControls.append(bottomBar)
|
|
602
603
|
|
|
603
|
-
|
|
604
|
-
const hasNoAudio = this.videoHasNoAudio()
|
|
605
|
-
if (hasNoAudio) {
|
|
606
|
-
this.muteIcon?.replaceWith(noAudioIcon)
|
|
607
|
-
}
|
|
608
|
-
})
|
|
604
|
+
// END CREATE ALL THE CUSTOM CONTOLS
|
|
609
605
|
|
|
610
606
|
video.addEventListener('playing', () => {
|
|
611
607
|
//resize controls in case poster is different size than video at the end
|
|
@@ -653,20 +649,9 @@ class Clip extends ClipInterface {
|
|
|
653
649
|
}
|
|
654
650
|
})
|
|
655
651
|
|
|
656
|
-
video.addEventListener('waiting', () => {
|
|
657
|
-
this.showLoadingIndicator()
|
|
658
|
-
})
|
|
659
|
-
|
|
660
|
-
video.addEventListener('canplay', () => {
|
|
661
|
-
this.hideLoadingIndicator()
|
|
662
|
-
})
|
|
663
|
-
|
|
664
|
-
video.addEventListener('canplaythrough', () => {
|
|
665
|
-
this.hideLoadingIndicator()
|
|
666
|
-
})
|
|
667
|
-
|
|
668
652
|
this.resizeControls()
|
|
669
653
|
|
|
654
|
+
// EVENTS TO DO WITH READY STATE / LOADING STATUS
|
|
670
655
|
const onLoadedMetaData = () => {
|
|
671
656
|
this.resizeControls()
|
|
672
657
|
const duration = formatTime(this.getDuration())
|
|
@@ -677,12 +662,50 @@ class Clip extends ClipInterface {
|
|
|
677
662
|
this.containerEl.classList.add('cp-clip--ready')
|
|
678
663
|
}
|
|
679
664
|
|
|
665
|
+
const onLoadedData = () => {
|
|
666
|
+
const hasNoAudio = this.videoHasNoAudio()
|
|
667
|
+
if (hasNoAudio) {
|
|
668
|
+
this.muteIcon?.replaceWith(noAudioIcon)
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
|
|
680
672
|
if (video.readyState >= 1) {
|
|
681
673
|
onLoadedMetaData()
|
|
682
674
|
} else {
|
|
683
675
|
video.addEventListener('loadedmetadata', onLoadedMetaData)
|
|
684
676
|
}
|
|
685
677
|
|
|
678
|
+
if (video.readyState >= 2) {
|
|
679
|
+
onLoadedData()
|
|
680
|
+
} else {
|
|
681
|
+
video.addEventListener('loadeddata', () => {
|
|
682
|
+
onLoadedData()
|
|
683
|
+
})
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
if (video.readyState >= 3) {
|
|
687
|
+
this.hideLoadingIndicator()
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
// NB: videos can go back and forth between readystates 2 and 3
|
|
691
|
+
|
|
692
|
+
// will fire when video drops from readystate >=3 to readystate <=2
|
|
693
|
+
video.addEventListener('waiting', () => {
|
|
694
|
+
this.showLoadingIndicator()
|
|
695
|
+
})
|
|
696
|
+
|
|
697
|
+
// will fire when video goes from readystate <=2 to 3
|
|
698
|
+
video.addEventListener('canplay', () => {
|
|
699
|
+
this.hideLoadingIndicator()
|
|
700
|
+
})
|
|
701
|
+
|
|
702
|
+
// will fire when video gets to readystate 4
|
|
703
|
+
video.addEventListener('canplaythrough', () => {
|
|
704
|
+
this.hideLoadingIndicator()
|
|
705
|
+
})
|
|
706
|
+
|
|
707
|
+
// END EVENTS TO DO WITH READY STATE / LOADING STATUS
|
|
708
|
+
|
|
686
709
|
customControls.addEventListener('click', (event) => {
|
|
687
710
|
const isVisible = isElementVisible(customControls)
|
|
688
711
|
this.fadeIn()
|
|
@@ -33,6 +33,27 @@ export const inlineVideoAutoplay = Clip({
|
|
|
33
33
|
],
|
|
34
34
|
},
|
|
35
35
|
})
|
|
36
|
+
export const inlineVideoNoAudio = Clip({
|
|
37
|
+
dataLayout: 'in-line',
|
|
38
|
+
url: 'https://d1e00ek4ebabms.cloudfront.net/production/84d7e1b0-e8b2-4ffc-a798-306f29dc9d52.png',
|
|
39
|
+
description:
|
|
40
|
+
' Dolor sit amet, consectetur adipiscing elit. Sed sit amet odio quis ante auctor dapibus. Sed dapibus cursus nisi, tincidunt sagittis sapien vehicula vitae.',
|
|
41
|
+
poster:
|
|
42
|
+
'https://www.ft.com/__origami/service/image/v2/images/raw/https%3A%2F%2Fd1e00ek4ebabms.cloudfront.net%2Fproduction%2F84d7e1b0-e8b2-4ffc-a798-306f29dc9d52.png?fit=scale-down&source=next&width=700',
|
|
43
|
+
caption: 'Aenean lobortis volutpat nunc vitae elementum',
|
|
44
|
+
autoplay: true,
|
|
45
|
+
muted: true,
|
|
46
|
+
loop: true,
|
|
47
|
+
noAudio: true,
|
|
48
|
+
credits: 'Copyright Line',
|
|
49
|
+
accessibility: {
|
|
50
|
+
captions: [
|
|
51
|
+
{
|
|
52
|
+
url: 'https://next-media-api.ft.com/captions/16862228218010.vtt',
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
},
|
|
56
|
+
})
|
|
36
57
|
|
|
37
58
|
export const teaserClipWithoutExpander = Clip({
|
|
38
59
|
dataLayout: 'in-line',
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import {
|
|
5
5
|
inlineVideo,
|
|
6
6
|
inlineVideoAutoplay,
|
|
7
|
+
inlineVideoNoAudio,
|
|
7
8
|
teaserClipWithMultipleSources,
|
|
8
9
|
teaserClipWithoutExpander,
|
|
9
10
|
} from './fixtures'
|
|
@@ -33,6 +34,9 @@ initialMocks()
|
|
|
33
34
|
|
|
34
35
|
const mockVideo = (video) => {
|
|
35
36
|
let playInterval = null
|
|
37
|
+
video.dispatchEvent(new Event('loadeddata'))
|
|
38
|
+
video.dispatchEvent(new Event('canplay'))
|
|
39
|
+
video.dispatchEvent(new Event('canplaythrough'))
|
|
36
40
|
video.load = () => {
|
|
37
41
|
/* do nothing */
|
|
38
42
|
}
|
|
@@ -43,7 +47,6 @@ const mockVideo = (video) => {
|
|
|
43
47
|
//mock that the video has a duration of 10 seconds when we play it due it is fully loaded
|
|
44
48
|
video.duration = 10000
|
|
45
49
|
video.paused = false
|
|
46
|
-
video.dispatchEvent(new Event('loadeddata'))
|
|
47
50
|
video.dispatchEvent(new Event('playing'))
|
|
48
51
|
}
|
|
49
52
|
video.pause = () => {
|
|
@@ -413,6 +416,52 @@ describe('Clip', () => {
|
|
|
413
416
|
})
|
|
414
417
|
})
|
|
415
418
|
|
|
419
|
+
describe('with no audio', () => {
|
|
420
|
+
let clips: Array<Clip>
|
|
421
|
+
|
|
422
|
+
beforeEach(() => {
|
|
423
|
+
document.body.innerHTML = inlineVideoNoAudio
|
|
424
|
+
clips = Clip.init()
|
|
425
|
+
mockClips(clips)
|
|
426
|
+
})
|
|
427
|
+
|
|
428
|
+
afterEach(() => {
|
|
429
|
+
const elem = document.body.children[0]
|
|
430
|
+
document.body.removeChild(elem)
|
|
431
|
+
clips.forEach((clip) => clip.destroy())
|
|
432
|
+
})
|
|
433
|
+
|
|
434
|
+
it("if the video doesn't have audio it should show 'no audio' icon after playing", (done) => {
|
|
435
|
+
const clip = clips[0]
|
|
436
|
+
expect(clip.muted).toBe(true)
|
|
437
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
438
|
+
const listener = (e) => {
|
|
439
|
+
expect(clip.muted).toBe(true)
|
|
440
|
+
expect(
|
|
441
|
+
clip.containerEl.querySelector('.cp-clip__no-audio')
|
|
442
|
+
).toBeTruthy()
|
|
443
|
+
clip.videoEl.removeEventListener('playing', listener)
|
|
444
|
+
done()
|
|
445
|
+
}
|
|
446
|
+
clip.videoEl.addEventListener('playing', listener)
|
|
447
|
+
clip.videoEl.play()
|
|
448
|
+
})
|
|
449
|
+
it("if the video doesn't have audio it shouldn't show mute icon after playing", (done) => {
|
|
450
|
+
const clip = clips[0]
|
|
451
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
452
|
+
const listener = (e) => {
|
|
453
|
+
expect(clip.muted).toBe(true)
|
|
454
|
+
expect(
|
|
455
|
+
clip.containerEl.querySelector('[data-test-id="cp-clip__mute-icon"]')
|
|
456
|
+
).toBeFalsy()
|
|
457
|
+
clip.videoEl.removeEventListener('playing', listener)
|
|
458
|
+
done()
|
|
459
|
+
}
|
|
460
|
+
clip.videoEl.addEventListener('playing', listener)
|
|
461
|
+
clip.videoEl.play()
|
|
462
|
+
})
|
|
463
|
+
})
|
|
464
|
+
|
|
416
465
|
describe('with autoplay', () => {
|
|
417
466
|
let clips: Array<Clip>
|
|
418
467
|
|
|
@@ -584,23 +633,6 @@ describe('Clip', () => {
|
|
|
584
633
|
clip.videoEl.play()
|
|
585
634
|
})
|
|
586
635
|
|
|
587
|
-
it("if the video doesn't have audio it shouldn't show mute icon after playing", (done) => {
|
|
588
|
-
const clip = clips[0]
|
|
589
|
-
clip.opts.noAudio = true
|
|
590
|
-
expect(clip.muted).toBe(true)
|
|
591
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
592
|
-
const listener = (e) => {
|
|
593
|
-
expect(clip.muted).toBe(true)
|
|
594
|
-
expect(
|
|
595
|
-
clip.containerEl.querySelector('[data-test-id="cp-clip__mute-icon"]')
|
|
596
|
-
).toBeFalsy()
|
|
597
|
-
clip.videoEl.removeEventListener('playing', listener)
|
|
598
|
-
done()
|
|
599
|
-
}
|
|
600
|
-
clip.videoEl.addEventListener('playing', listener)
|
|
601
|
-
clip.videoEl.play()
|
|
602
|
-
})
|
|
603
|
-
|
|
604
636
|
it('mute icon should change and set or unset the video muted', (done) => {
|
|
605
637
|
const clip = clips[0]
|
|
606
638
|
expect(clip.muted).toBe(true)
|
|
@@ -627,23 +659,6 @@ describe('Clip', () => {
|
|
|
627
659
|
clip.muteIcon.click()
|
|
628
660
|
})
|
|
629
661
|
|
|
630
|
-
it("if the video doesn't have audio it should show no audio icon after playing", (done) => {
|
|
631
|
-
const clip = clips[0]
|
|
632
|
-
clip.opts.noAudio = true
|
|
633
|
-
expect(clip.muted).toBe(true)
|
|
634
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
635
|
-
const listener = (e) => {
|
|
636
|
-
expect(clip.muted).toBe(true)
|
|
637
|
-
expect(
|
|
638
|
-
clip.containerEl.querySelector('.cp-clip__no-audio')
|
|
639
|
-
).toBeTruthy()
|
|
640
|
-
clip.videoEl.removeEventListener('playing', listener)
|
|
641
|
-
done()
|
|
642
|
-
}
|
|
643
|
-
clip.videoEl.addEventListener('playing', listener)
|
|
644
|
-
clip.videoEl.play()
|
|
645
|
-
})
|
|
646
|
-
|
|
647
662
|
it('should assing empty string to the poster attribute if autoplay mode is enabled', () => {
|
|
648
663
|
const clip = clips[0]
|
|
649
664
|
expect(clip.videoEl.getAttribute('poster')).toBe('')
|