ArticleTemplates/assets/js/bootstraps/audio.js (88 lines of code) (raw):
import { getElementOffset, debounce, signalDevice } from 'modules/util';
let audioCurrent;
let down;
let slider1;
let previous = 0;
function getColor() {
const isAudio = !document.body.classList.contains('tone--podcast') && document.body.classList.contains('article--audio');
return GU.opts.isAdvertising ? 'rgba(105, 209, 202, 0.15)' : (isAudio ? 'rgba(255, 187, 0, 0.05)' : 'rgba(167, 216, 242, 0.10)');
}
function secondsTimeSpanToHMS(s) {
const m = Math.floor(s / 60);
s -= m * 60;
return `${m < 10 ? '0' + m : m}:${s < 10 ? '0' + s : s}`;
}
function superAudioSlider(current, duration, platform) {
let audioPlayerSliderKnob;
const cutoutContainer = document.getElementsByClassName('cutout__container')[0];
if (platform === 'iOS') {
if (down === 1) {
return;
}
} else if ((!cutoutContainer || !cutoutContainer.dataset.background) && !document.body.classList.contains('media')) {
window.audioBackground(duration);
window.addEventListener('resize', debounce(() => {
window.audioBackground(duration);
}, 100));
}
audioPlayerSliderKnob = document.getElementsByClassName('audio-player__slider__knob')[0];
if (audioPlayerSliderKnob) {
audioPlayerSliderKnob.removeAttribute('style');
}
slider1 = new MobileRangeSlider(document.querySelector('.audio-player__slider'), {
value: current,
min: 0,
max: duration,
change: changeSlider.bind(null, duration)
});
}
function changeSlider(duration, percentage) {
const audioPlayerSliderPlayed = document.getElementsByClassName('audio-player__slider__played')[0];
const audioPlayerSliderRemaining = document.getElementsByClassName('audio-player__slider__remaining')[0];
audioCurrent = percentage;
if (audioPlayerSliderPlayed) {
audioPlayerSliderPlayed.value = secondsTimeSpanToHMS(percentage);
}
if (audioPlayerSliderRemaining) {
const remaining = secondsTimeSpanToHMS(duration - percentage);
audioPlayerSliderRemaining.value = percentage ? `-${remaining}` : `${remaining}`;
}
}
function updateSlider(current, platform) {
if (platform === 'iOS') {
if (down === 1) {
return;
}
}
slider1.setValue(current);
if (current - previous === 1) {
audioPlaying();
} else if (current === previous) {
audioStop();
}
previous = current;
}
function audioSlider() {
document.addEventListener('touchstart', () => {
down = 1;
}, false);
document.addEventListener('touchend', () => {
down = 0;
}, false);
/* Caution: Hot Mess */
MobileRangeSlider.prototype.start = function () {
if (GU.opts.platform === 'android') {
window.GuardianJSInterface.registerRelatedCardsTouch(true);
}
this.addEvents('move');
this.addEvents('end');
this.handle(event);
};
/* Caution: Hot Mess */
MobileRangeSlider.prototype.end = function () {
if (GU.opts.platform === 'android') {
window.GuardianJSInterface.registerRelatedCardsTouch(false);
}
this.removeEvents('move');
this.removeEvents('end');
signalDevice(`setPlayerTime/${audioCurrent}`);
};
}
function audioPlay() {
const audioPlayer = document.getElementsByClassName('audio-player')[0];
if (audioPlayer) {
audioPlayer.classList.add('loading');
}
}
function audioPlaying() {
const button = document.getElementsByClassName('audio-player__button')[0];
const audioPlayer = document.getElementsByClassName('audio-player')[0];
const screenReadable = document.getElementsByClassName('audio-player-readable')[0];
if (button && audioPlayer && screenReadable) {
button.classList.add('pause');
audioPlayer.classList.remove('loading');
screenReadable.innerHTML = "Pause";
}
}
function audioStop() {
const button = document.getElementsByClassName('audio-player__button')[0];
const screenReadable = document.getElementsByClassName('audio-player-readable')[0];
if (button && screenReadable) {
button.classList.remove('pause');
screenReadable.innerHTML = "Play";
}
}
function audioLoad() {
const audioPlayer = document.getElementsByClassName('audio-player')[0];
audioPlayer.classList.add('loading');
}
function audioFinishLoad() {
var audioPlayer = document.getElementsByClassName('audio-player')[0];
audioPlayer.classList.remove('loading');
}
function audioBackground(duration) {
const cutoutBackground = document.getElementsByClassName('cutout__background')[0];
const cutoutContainer = document.getElementsByClassName('cutout__container')[0];
if (cutoutBackground) {
cutoutBackground.parentNode.removeChild(cutoutBackground);
}
if (cutoutContainer) {
styleCutoutContainer(duration, cutoutContainer);
}
}
function styleCutoutContainer(duration, cutoutContainer) {
const articleHeader = document.getElementsByClassName('article__header')[0];
const numOfCircles = Math.min(10, Math.floor((duration / 60) / 2)) + 2;
const h = getElementOffset(cutoutContainer).height;
const w = getElementOffset(cutoutContainer).width;
let size = (h * w) / 8000;
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = w;
canvas.height = h;
canvas.className = 'cutout__background';
// Draw Circles
for (let i = 0; i < numOfCircles; i++) {
const x = Math.floor(Math.random() * (w - 0) + 1);
ctx.beginPath();
ctx.arc(x, h / 2, size, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = getColor();
ctx.fill();
size = size * 1.2;
}
articleHeader.appendChild(canvas);
cutoutContainer.dataset.background = 'true';
}
/**
* Hide the existing podcast controls and adjust the height they take up
* so they can be replaced by native controls.
* When called returns (and sends via signalDevice) the relative position and size of the player container area
* By relative this means relative to the top left corner of the page, it does not change as page is scrolled.
* @param {number} desiredHeight - Height of native player that will replace this player
* @returns {object} elementOffset - { top, left, height, width } (object can be null if container not found)
*/
function hidePodcastPlayer(desiredHeight) {
const playerContainer = document.getElementsByClassName('audio-player__container')[0];
if (playerContainer) {
if (desiredHeight > 0) {
playerContainer.style.opacity = 0;
playerContainer.style.height = desiredHeight + 'px';
} else {
playerContainer.style.display = 'none';
}
const offset = getElementOffset(playerContainer);
signalDevice(JSON.stringify(offset));
return offset;
}
return null;
}
function showNewAudioPlayer() {
const playerContainer = document.getElementsByClassName('audio-player__container')[0];
if (playerContainer) {
playerContainer.style.display = 'none';
}
const playerContainerNew = document.getElementsByClassName('audio-player__container_new')[0];
if (playerContainerNew) {
playerContainerNew.style.display = 'block';
}
}
function setAudioDuration(duration) {
const audioDuration = document.getElementsByClassName('audio-player__info__duration')[0];
if (audioDuration) {
audioDuration.textContent = duration;
}
}
function newAudioPlayerLoading() {
const newAudioPlayerContainer = document.getElementsByClassName('audio-player__container_new')[0];
if (newAudioPlayerContainer) {
const audioPlayer = newAudioPlayerContainer.getElementsByClassName('audio-player')[0];
if (audioPlayer) {
audioPlayer.classList.add('loading');
}
}
}
function newAudioPlayerPlaying() {
const newAudioPlayerContainer = document.getElementsByClassName('audio-player__container_new')[0];
if (newAudioPlayerContainer) {
const button = newAudioPlayerContainer.getElementsByClassName('audio-player__button')[0];
const audioPlayer = newAudioPlayerContainer.getElementsByClassName('audio-player')[0];
const screenReadable = newAudioPlayerContainer.getElementsByClassName('audio-player-readable')[0];
if (button && audioPlayer && screenReadable) {
const href = button.getAttribute('href');
button.setAttribute('href', href.replace(/x-gu:\/\/(playaudio|pauseaudio)\/(.*)/, 'x-gu://pauseaudio/$2'));
button.classList.add('pause');
audioPlayer.classList.remove('loading');
screenReadable.innerHTML = 'Pause';
}
}
}
function newAudioPlayerStopped() {
const newAudioPlayerContainer = document.getElementsByClassName('audio-player__container_new')[0];
if (newAudioPlayerContainer) {
const button = newAudioPlayerContainer.getElementsByClassName('audio-player__button')[0];
const audioPlayer = newAudioPlayerContainer.getElementsByClassName('audio-player')[0];
const screenReadable = newAudioPlayerContainer.getElementsByClassName('audio-player-readable')[0];
if (button && audioPlayer && screenReadable) {
const href = button.getAttribute('href');
button.setAttribute('href', href.replace(/x-gu:\/\/(playaudio|pauseaudio)\/(.*)/, 'x-gu://playaudio/$2'));
button.classList.remove('pause');
audioPlayer.classList.remove('loading');
screenReadable.innerHTML = "Play";
}
}
}
function setupGlobals() {
// Global function to handle audio, called by native code
window.superAudioSlider = superAudioSlider;
window.updateSlider = updateSlider;
window.audioPlay = audioPlay;
window.audioStop = audioStop;
window.audioLoad = audioLoad;
window.audioFinishLoad = audioFinishLoad;
window.audioBackground = audioBackground;
window.hidePodcastPlayer = hidePodcastPlayer;
window.showNewAudioPlayer = showNewAudioPlayer;
window.setAudioDuration = setAudioDuration;
window.newAudioPlayerLoading = newAudioPlayerLoading;
window.newAudioPlayerPlaying = newAudioPlayerPlaying;
window.newAudioPlayerStopped = newAudioPlayerStopped;
window.applyNativeFunctionCall('audioBackground');
window.applyNativeFunctionCall('superAudioSlider');
window.applyNativeFunctionCall('audioPlay');
window.applyNativeFunctionCall('audioStop');
}
function init() {
audioSlider();
setupGlobals();
}
export { init, changeSlider };