class MusicMemory extends HTMLElement { constructor() { super(); this.selectedRanges = []; this.currentButtons = []; this.noShuffle = this.hasAttribute('no-shuffle') || false; this.debug = this.hasAttribute('debug') || false; this.audioElements = []; this.activeTimeout = null; } connectedCallback() { this.initializeAudioElements(); } initializeAudioElements() { let buttons = []; this.querySelectorAll('audio').forEach((audio, index) => { this.audioElements.push(audio); ['range1', 'range2'].forEach(rangeKey => { const button = document.createElement('button'); button.textContent = this.debug ? `Play ${index + 1}.${rangeKey === 'range1' ? '1' : '2'}` : 'Play'; button.addEventListener('click', () => this.handlePlay(audio, audio.dataset[rangeKey], button)); buttons.push(button); }); }); if (!this.noShuffle) { buttons = this.shuffleArray(buttons); } buttons.forEach(button => this.appendChild(button)); } shuffleArray(array) { for (let i = array.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [array[i], array[j]] = [array[j], array[i]]; } return array; } handlePlay(audio, rangeData, button) { this.stopAllAudios(); this.clearActiveTimeout(); // This handles the case where the user clicks a button after two were already clicked but didn't reset if (this.currentButtons.length === 2 && !this.currentButtons.every(btn => btn.classList.contains('matched'))) { this.currentButtons.forEach(btn => { btn.disabled = false; }); this.currentButtons = []; } this.currentButtons.push(button); button.disabled = true; if (this.checkForMatch(audio)) { this.currentButtons.forEach(button => button.classList.add('matched')); this.currentButtons = []; return; }; const [start, end] = this.parseRange(rangeData); audio.currentTime = 0; audio.currentTime = start / 1000; audio.play(); const playDuration = (end - start) / 1000; this.activeTimeout = setTimeout(() => { audio.pause(); audio.currentTime = 0; if (this.currentButtons.length === 2) { this.currentButtons.forEach(button => button.disabled = false); this.currentButtons = []; } }, playDuration * 1000); } parseRange(rangeData) { return rangeData.split('-').map(Number); } checkForMatch(selectedAudio) { this.selectedRanges.push(selectedAudio); if (this.selectedRanges.length === 2) { if (this.selectedRanges[0].src === this.selectedRanges[1].src) { this.playFullAudio(this.selectedRanges[0]); this.selectedRanges = []; return true; } this.selectedRanges = []; } return false; } playFullAudio(audio) { audio.currentTime = 0; const end = audio.dataset['range2'].split('-')[1]; audio.play(); setTimeout(() => { audio.pause(); audio.currentTime = 0; }, end); } stopAllAudios() { this.audioElements.forEach(audio => audio.pause()); } clearActiveTimeout() { if (this.activeTimeout) { clearTimeout(this.activeTimeout); this.activeTimeout = null; } } } customElements.define('music-memory', MusicMemory);