|
|
@ -10,6 +10,7 @@ import { isTouchSupported } from "../helpers/touchSupport"; |
|
|
|
import RangeSelector from "../components/rangeSelector"; |
|
|
|
import RangeSelector from "../components/rangeSelector"; |
|
|
|
import { onVideoLoad } from "../helpers/files"; |
|
|
|
import { onVideoLoad } from "../helpers/files"; |
|
|
|
import { cancelEvent } from "../helpers/dom/cancelEvent"; |
|
|
|
import { cancelEvent } from "../helpers/dom/cancelEvent"; |
|
|
|
|
|
|
|
import ListenerSetter from "../helpers/listenerSetter"; |
|
|
|
|
|
|
|
|
|
|
|
export class MediaProgressLine extends RangeSelector { |
|
|
|
export class MediaProgressLine extends RangeSelector { |
|
|
|
private filledLoad: HTMLDivElement; |
|
|
|
private filledLoad: HTMLDivElement; |
|
|
@ -165,17 +166,21 @@ export class MediaProgressLine extends RangeSelector { |
|
|
|
|
|
|
|
|
|
|
|
let lastVolume = 1, muted = !lastVolume; |
|
|
|
let lastVolume = 1, muted = !lastVolume; |
|
|
|
export default class VideoPlayer { |
|
|
|
export default class VideoPlayer { |
|
|
|
public wrapper: HTMLDivElement; |
|
|
|
private wrapper: HTMLDivElement; |
|
|
|
public progress: MediaProgressLine; |
|
|
|
private progress: MediaProgressLine; |
|
|
|
private skin: string; |
|
|
|
private skin: string; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private listenerSetter: ListenerSetter; |
|
|
|
|
|
|
|
|
|
|
|
/* private videoParent: HTMLElement; |
|
|
|
/* private videoParent: HTMLElement; |
|
|
|
private videoWhichChild: number; */ |
|
|
|
private videoWhichChild: number; */ |
|
|
|
|
|
|
|
|
|
|
|
constructor(public video: HTMLVideoElement, play = false, streamable = false, duration?: number) { |
|
|
|
constructor(private video: HTMLVideoElement, play = false, streamable = false, duration?: number) { |
|
|
|
this.wrapper = document.createElement('div'); |
|
|
|
this.wrapper = document.createElement('div'); |
|
|
|
this.wrapper.classList.add('ckin__player'); |
|
|
|
this.wrapper.classList.add('ckin__player'); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.listenerSetter = new ListenerSetter(); |
|
|
|
|
|
|
|
|
|
|
|
video.parentNode.insertBefore(this.wrapper, video); |
|
|
|
video.parentNode.insertBefore(this.wrapper, video); |
|
|
|
this.wrapper.appendChild(video); |
|
|
|
this.wrapper.appendChild(video); |
|
|
|
|
|
|
|
|
|
|
@ -184,7 +189,7 @@ export default class VideoPlayer { |
|
|
|
this.stylePlayer(duration); |
|
|
|
this.stylePlayer(duration); |
|
|
|
|
|
|
|
|
|
|
|
if(this.skin === 'default') { |
|
|
|
if(this.skin === 'default') { |
|
|
|
let controls = this.wrapper.querySelector('.default__controls.ckin__controls') as HTMLDivElement; |
|
|
|
const controls = this.wrapper.querySelector('.default__controls.ckin__controls') as HTMLDivElement; |
|
|
|
this.progress = new MediaProgressLine(video, streamable); |
|
|
|
this.progress = new MediaProgressLine(video, streamable); |
|
|
|
controls.prepend(this.progress.container); |
|
|
|
controls.prepend(this.progress.container); |
|
|
|
} |
|
|
|
} |
|
|
@ -228,10 +233,12 @@ export default class VideoPlayer { |
|
|
|
`;
|
|
|
|
`;
|
|
|
|
const volumeSvg = volumeDiv.firstElementChild as SVGSVGElement; |
|
|
|
const volumeSvg = volumeDiv.firstElementChild as SVGSVGElement; |
|
|
|
|
|
|
|
|
|
|
|
volumeSvg.addEventListener('click', (e) => { |
|
|
|
const onMuteClick = (e?: Event) => { |
|
|
|
cancelEvent(e); |
|
|
|
e && cancelEvent(e); |
|
|
|
video.muted = !video.muted; |
|
|
|
video.muted = !video.muted; |
|
|
|
}); |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.listenerSetter.add(volumeSvg, 'click', onMuteClick); |
|
|
|
|
|
|
|
|
|
|
|
const volumeProgress = new RangeSelector(0.01, 1, 0, 1); |
|
|
|
const volumeProgress = new RangeSelector(0.01, 1, 0, 1); |
|
|
|
volumeProgress.setListeners(); |
|
|
|
volumeProgress.setListeners(); |
|
|
@ -270,7 +277,7 @@ export default class VideoPlayer { |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// не вызовется повторно если на 1 установить 1
|
|
|
|
// не вызовется повторно если на 1 установить 1
|
|
|
|
video.addEventListener('volumechange', () => { |
|
|
|
this.listenerSetter.add(video, 'volumechange', () => { |
|
|
|
muted = video.muted; |
|
|
|
muted = video.muted; |
|
|
|
lastVolume = video.volume; |
|
|
|
lastVolume = video.volume; |
|
|
|
setVolume(); |
|
|
|
setVolume(); |
|
|
@ -287,46 +294,56 @@ export default class VideoPlayer { |
|
|
|
leftControls.insertBefore(volumeDiv, timeElapsed.parentElement); |
|
|
|
leftControls.insertBefore(volumeDiv, timeElapsed.parentElement); |
|
|
|
|
|
|
|
|
|
|
|
Array.from(toggle).forEach((button) => { |
|
|
|
Array.from(toggle).forEach((button) => { |
|
|
|
return button.addEventListener('click', () => { |
|
|
|
this.listenerSetter.add(button, 'click', () => { |
|
|
|
this.togglePlay(); |
|
|
|
this.togglePlay(); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
video.addEventListener('click', () => { |
|
|
|
this.listenerSetter.add(video, 'click', () => { |
|
|
|
if(!isTouchSupported) { |
|
|
|
if(!isTouchSupported) { |
|
|
|
this.togglePlay(); |
|
|
|
this.togglePlay(); |
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
if(isTouchSupported) { |
|
|
|
let showControlsTimeout = 0; |
|
|
|
let showControlsTimeout = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const t = () => { |
|
|
|
|
|
|
|
showControlsTimeout = window.setTimeout(() => { |
|
|
|
|
|
|
|
showControlsTimeout = 0; |
|
|
|
|
|
|
|
player.classList.remove('show-controls'); |
|
|
|
|
|
|
|
}, 3e3); |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
player.addEventListener('click', () => { |
|
|
|
|
|
|
|
if(showControlsTimeout) { |
|
|
|
|
|
|
|
clearTimeout(showControlsTimeout); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
player.classList.add('show-controls'); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
t(); |
|
|
|
const showControls = () => { |
|
|
|
|
|
|
|
if(showControlsTimeout) clearTimeout(showControlsTimeout); |
|
|
|
|
|
|
|
else player.classList.add('show-controls'); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
showControlsTimeout = window.setTimeout(() => { |
|
|
|
|
|
|
|
showControlsTimeout = 0; |
|
|
|
|
|
|
|
player.classList.remove('show-controls'); |
|
|
|
|
|
|
|
}, 3e3); |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(isTouchSupported) { |
|
|
|
|
|
|
|
this.listenerSetter.add(player, 'click', () => { |
|
|
|
|
|
|
|
showControls(); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
player.addEventListener('touchstart', () => { |
|
|
|
this.listenerSetter.add(player, 'touchstart', () => { |
|
|
|
player.classList.add('show-controls'); |
|
|
|
player.classList.add('show-controls'); |
|
|
|
clearTimeout(showControlsTimeout); |
|
|
|
clearTimeout(showControlsTimeout); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
player.addEventListener('touchend', () => { |
|
|
|
this.listenerSetter.add(player, 'touchend', () => { |
|
|
|
if(player.classList.contains('is-playing')) { |
|
|
|
if(player.classList.contains('is-playing')) { |
|
|
|
t(); |
|
|
|
showControls(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
this.listenerSetter.add(this.wrapper, 'mousemove', () => { |
|
|
|
|
|
|
|
showControls(); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.listenerSetter.add(document, 'keydown', (e: KeyboardEvent) => { |
|
|
|
|
|
|
|
if(e.code === 'KeyF') { |
|
|
|
|
|
|
|
this.toggleFullScreen(fullScreenButton); |
|
|
|
|
|
|
|
} else if(e.code === 'KeyM') { |
|
|
|
|
|
|
|
onMuteClick(); |
|
|
|
|
|
|
|
} else if(e.code === 'Space') { |
|
|
|
|
|
|
|
this.togglePlay(); |
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
@ -342,32 +359,34 @@ export default class VideoPlayer { |
|
|
|
/* video.addEventListener('play', () => { |
|
|
|
/* video.addEventListener('play', () => { |
|
|
|
}); */ |
|
|
|
}); */ |
|
|
|
|
|
|
|
|
|
|
|
video.addEventListener('dblclick', () => { |
|
|
|
this.listenerSetter.add(video, 'dblclick', () => { |
|
|
|
if(isTouchSupported) { |
|
|
|
if(!isTouchSupported) { |
|
|
|
return; |
|
|
|
this.toggleFullScreen(fullScreenButton); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
return this.toggleFullScreen(fullScreenButton); |
|
|
|
this.listenerSetter.add(fullScreenButton, 'click', (e) => { |
|
|
|
}) |
|
|
|
this.toggleFullScreen(fullScreenButton); |
|
|
|
|
|
|
|
|
|
|
|
fullScreenButton.addEventListener('click', (e) => { |
|
|
|
|
|
|
|
return this.toggleFullScreen(fullScreenButton); |
|
|
|
|
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
'webkitfullscreenchange mozfullscreenchange fullscreenchange MSFullscreenChange'.split(' ').forEach(eventName => { |
|
|
|
'webkitfullscreenchange mozfullscreenchange fullscreenchange MSFullscreenChange'.split(' ').forEach(eventName => { |
|
|
|
player.addEventListener(eventName, this.onFullScreen, false); |
|
|
|
this.listenerSetter.add(player, eventName, this.onFullScreen, false); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
video.addEventListener('timeupdate', () => { |
|
|
|
this.listenerSetter.add(video, 'timeupdate', () => { |
|
|
|
timeElapsed.innerHTML = String(video.currentTime | 0).toHHMMSS(); |
|
|
|
timeElapsed.innerHTML = String(video.currentTime | 0).toHHMMSS(); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.listenerSetter.add(video, 'play', () => { |
|
|
|
|
|
|
|
this.wrapper.classList.add('played'); |
|
|
|
|
|
|
|
}, {once: true}); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
video.addEventListener('play', () => { |
|
|
|
this.listenerSetter.add(video, 'play', () => { |
|
|
|
this.wrapper.classList.add('is-playing'); |
|
|
|
this.wrapper.classList.add('is-playing'); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
video.addEventListener('pause', () => { |
|
|
|
this.listenerSetter.add(video, 'pause', () => { |
|
|
|
this.wrapper.classList.remove('is-playing'); |
|
|
|
this.wrapper.classList.remove('is-playing'); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
@ -380,21 +399,8 @@ export default class VideoPlayer { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public togglePlay(stop?: boolean) { |
|
|
|
public togglePlay() { |
|
|
|
//console.log('video togglePlay:', stop, this.video.paused);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(stop) { |
|
|
|
|
|
|
|
this.video.pause(); |
|
|
|
|
|
|
|
this.wrapper.classList.remove('is-playing'); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} else if(stop === false) { |
|
|
|
|
|
|
|
this.video.play(); |
|
|
|
|
|
|
|
this.wrapper.classList.add('is-playing'); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.video[this.video.paused ? 'play' : 'pause'](); |
|
|
|
this.video[this.video.paused ? 'play' : 'pause'](); |
|
|
|
//this.wrapper.classList.toggle('is-playing', !this.video.paused);
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private buildControls() { |
|
|
|
private buildControls() { |
|
|
@ -514,7 +520,11 @@ export default class VideoPlayer { |
|
|
|
const isFullscreenNow = document.webkitFullscreenElement !== null; |
|
|
|
const isFullscreenNow = document.webkitFullscreenElement !== null; |
|
|
|
if(!isFullscreenNow) { |
|
|
|
if(!isFullscreenNow) { |
|
|
|
this.wrapper.classList.remove('ckin__fullscreen'); |
|
|
|
this.wrapper.classList.remove('ckin__fullscreen'); |
|
|
|
} else { |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public removeListeners() { |
|
|
|
|
|
|
|
this.listenerSetter.removeAll(); |
|
|
|
|
|
|
|
this.progress.removeListeners(); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|