Пытаясь сделать кастомный аудиоплеер для добавления аудиозаписей на сайт(взял за основу чей-то код), столкнулся с проблемой. Почему-то работает только один плеер на странице - тот, который создаётся последним. При попытке проиграть что-нибудь другое в консоли появляется ошибка(Ошибка при парсинге значения «margin-left»), быстро набирающая повторы. В итоге ничего толком не запускается. Притом такая ситуация возникает у меня в Firefox 52.6.0.6592, тогда как в Firefox 42-43 и Chrome 49.0 вроде бы всё нормально.
Вот сайт:
https://m-ch.ml/t/wakaba.html
Код для плеера:
//array for post ids
var num = [];
// array for AudioObjects
var audioList = [];
// components and the index for their AudioObject
var componentDict = {};
// store AudioObject that is currently playing
var playingAudio = null;
// store playhead id if one is being dragged
var onplayhead = null;
function getThreadNums ()
{
var audioElements = document.getElementsByClassName("audio"), i;
for (i = 0; i < audioElements.length; i++) {
num[i]=audioElements[i].id;
num[i]=num[i].slice(6);
// window.alert(i+ " " + num[i]);
}
}
getThreadNums();
/* AudioObject Constructor */
function AudioObject(audio, duration) {
this.audio = audio;
this.id = audio;
this.duration = duration;
}
AudioObject.prototype.bindAudioPlayer = function (num) {
this.audioplayer = document.getElementById("audioplayer-" + num);
this.playbutton = document.getElementById("playbutton-" + num);
this.timeline = document.getElementById("timeline-" + num);
this.playhead = document.getElementById("playhead-" + num);
this.runtime = document.getElementById("runtime-" + num);
this.range = document.getElementById("range-" + num);
this.volume = document.getElementById("volume-" + num);
this.timelineWidth = this.timeline.offsetWidth - this.playhead.offsetWidth;
}
/* addEventListeners() */
AudioObject.prototype.addEventListeners = function () {
this.audio.addEventListener("timeupdate", AudioObject.prototype.timeUpdate, false);
this.audio.addEventListener("durationchange", AudioObject.prototype.durationChange, false);
this.audio.addEventListener("volumechange", AudioObject.prototype.volumeChange, false);
this.timeline.addEventListener("click", AudioObject.prototype.timelineClick, false);
this.playbutton.addEventListener("click", AudioObject.prototype.pressPlay, false);
// Makes playhead draggable
this.playhead.addEventListener('mousedown', AudioObject.prototype.mouseDown, false);
window.addEventListener('mouseup', mouseUp, false);
}
/* populateAudioList */
function populateAudioList() {
var audioElements = document.getElementsByClassName("audio"), i;
for (i = 0; i < audioElements.length; i++) {
audioList.push(new AudioObject(audioElements[i], 0));
audioList[i].bindAudioPlayer(num[i]);
audioList[i].addEventListeners();
}
}
/* populateComponentDictionary()
* {key=element id : value=index of audioList} */
function populateComponentDictionary() {
for (i = 0; i < audioList.length; i++) {
componentDict[audioList[i].audio.id] = i;
componentDict[audioList[i].playbutton.id] = i;
componentDict[audioList[i].timeline.id] = i;
componentDict[audioList[i].playhead.id] = i;
componentDict[audioList[i].runtime.id] = i;
componentDict[audioList[i].range.id] = i;
componentDict[audioList[i].volume.id] = i;
}
}
///////////////////////////////////////////////
// Update Audio Player
///////////////////////////////////////////////
/* durationChange
* set duration for AudioObject */
AudioObject.prototype.durationChange = function () {
var ao = audioList[getAudioListIndex(this.id)];
ao.duration = this.duration;
}
/* pressPlay()
* call play() for correct AudioObject
*/
AudioObject.prototype.pressPlay = function () {
var index = getAudioListIndex(this.id);
audioList[index].play();
}
/* play()
* play or pause selected audio, if there is a song playing pause it
*/
AudioObject.prototype.play = function () {
if (this == playingAudio) {
playingAudio = null;
this.audio.pause();
changeClass(this.playbutton, "play");
}
// else check if playing audio exists and pause it, then start this
else {
if (playingAudio != null) {
playingAudio.audio.pause();
changeClass(playingAudio.playbutton, "play");
}
/*var a1 = document.getElementById(this.audio.id);
a1.play();*/
this.audio.play();
playingAudio = this;
changeClass(this.playbutton, "pause");
}
}
/* timelineClick()
* get timeline's AudioObject
*/
AudioObject.prototype.timelineClick = function (event) {
var ao = audioList[getAudioListIndex(this.id)];
ao.audio.currentTime = ao.audio.duration * clickPercent(event, ao.timeline, ao.timelineWidth);
}
/* mouseDown */
AudioObject.prototype.mouseDown = function (event) {
onplayhead = this.id;
var ao = audioList[getAudioListIndex(this.id)];
window.addEventListener('mousemove', AudioObject.prototype.moveplayhead, true);
ao.audio.removeEventListener('timeupdate', AudioObject.prototype.timeUpdate, false);
}
/* mouseUp EventListener
* getting input from all mouse clicks */
function mouseUp(e) {
if (onplayhead != null) {
var ao = audioList[getAudioListIndex(onplayhead)];
window.removeEventListener('mousemove', AudioObject.prototype.moveplayhead, true);
// change current time
ao.audio.currentTime = ao.audio.duration * clickPercent(e, ao.timeline, ao.timelineWidth);
ao.audio.addEventListener('timeupdate', AudioObject.prototype.timeUpdate, false);
}
onplayhead = null;
}
/* mousemove EventListener
* Moves playhead as user drags */
AudioObject.prototype.moveplayhead = function (e) {
var ao = audioList[getAudioListIndex(onplayhead)];
var newMargLeft = e.clientX - getPosition(ao.timeline);
if (newMargLeft >= 0 && newMargLeft <= ao.timelineWidth) {
document.getElementById(onplayhead).style.marginLeft = newMargLeft + "px";
}
if (newMargLeft < 0) {
playhead.style.marginLeft = "0px";
}
if (newMargLeft > ao.timelineWidth) {
playhead.style.marginLeft = ao.timelineWidth + "px";
}
}
/* timeUpdate
* Synchronizes playhead position with current point in audio
* this is the html audio element
*/
AudioObject.prototype.timeUpdate = function () {
// audio element's AudioObject
var ao = audioList[getAudioListIndex(this.id)];
var playPercent = ao.timelineWidth * (ao.audio.currentTime / ao.duration);
ao.playhead.style.marginLeft = playPercent + "px";
// If song is over
var minutes = parseInt(ao.duration / 60, 10);
var seconds = parseInt(ao.duration % 60);
var cminutes = parseInt(ao.audio.currentTime / 60, 10);
var cseconds = parseInt(ao.audio.currentTime % 60);
document.getElementById("runtime-" + num[getAudioListIndex(this.id)] ).innerHTML=cminutes+":"+cseconds+"/"+minutes+":"+seconds;
if (ao.audio.currentTime == ao.duration) {
changeClass(ao.playbutton, "play");
ao.audio.currentTime = 0;
ao.audio.pause();
playingAudio = null;
}
}
function setVolume(vid) {
vid=vid.slice(6);
var slider = document.getElementById("range-" + vid);
var output = document.getElementById("volume-" + vid);
var music = document.getElementById("audio-" + vid);
output.innerHTML = "Vol:" + Math.round(slider.value*100)+"%";
music.volume = slider.value;
}
///////////////////////////////////////////////
// Utility Methods
///////////////////////////////////////////////
/* changeClass
* overwrites element's class names */
function changeClass(element, newClasses) {
element.className = newClasses;
}
/* getAudioListIndex
* Given an element's id, find the index in audioList for the correct AudioObject */
function getAudioListIndex(id) {
return componentDict[id];
}
/* clickPercent()
* returns click as decimal (.77) of the total timelineWidth */
function clickPercent(e, timeline, timelineWidth) {
return ((e.clientX - getPosition(timeline))/ timelineWidth);
}
// getPosition
// Returns elements left position relative to top-left of viewport
function getPosition(el) {
return el.getBoundingClientRect().left;
}
populateAudioList();
populateComponentDictionary();