class SubClass constructor: ( parent , data ) -> @.root = parent.root or parent @.parent = parent @.init? data class Words extends SubClass template: "
" list: [] elements: [] init: -> @.getElements() @.addListeners() getElements: -> @.sliderContainer = document.querySelector ".words" @.elementContainer = document.querySelector ".words .slider" @.elements = document.querySelectorAll ".word" @.newWordButton = document.querySelector ".add-words" for element in @.elements @.addItemListeners element addListeners: -> @.newWordButton.addEventListener "click" , @.makeNewWordElement @.elementContainer.addEventListener "mousewheel" , @.onScroll onScroll: ( e ) => e.preventDefault() @.sliderContainer.scrollLeft += e.deltaY @.sliderContainer.scrollLeft += e.deltaX makeNewWordElement: => item = document.createElement "li" item.setAttribute "class" , "word" item.innerHTML = @.template last = @.elementContainer.lastChild @.elementContainer.insertBefore item , last @.addItemListeners item item.querySelector(".string").focus() addItemListeners: ( item ) -> item.querySelector( ".delete" ).onclick = @.deleteItem item.querySelector( ".play" ).onclick = => @.root.parse.item item item.querySelector( ".string" ).onchange = => @.root.parse.item item item.querySelector( ".pitch" ).onchange = => pitch = item.querySelector( ".pitch" ).value / 100 item.querySelector( ".string" ).style.top = "#{100 - (10+ ( pitch / 2 * 80 ))}%" @.root.parse.item item item.querySelector( ".rate" ).onchange = => @.root.parse.item item pitch = item.querySelector( ".pitch" ).value / 100 item.querySelector( ".string" ).style.top = "#{100 - (10+ ( pitch / 2 * 80 ))}%" deleteItem: ( event ) => item = event.srcElement.parentNode.parentNode item.parentNode.removeChild item class Parse extends SubClass voice: null utterances: [] init: -> voices = window.speechSynthesis.getVoices() select = document.querySelector ".voice-name" if voices.length is 0 setTimeout => @.init() , 100 else for voice in voices if voice.name.substring( 0, 6 ) isnt "Google" option = document.createElement "option" option.text = voice.name option.voice = voice select.appendChild option item: ( item ) => @.utterances = [] voices = speechSynthesis.getVoices() name = document.querySelector ".voice-name" voice = name[ name.selectedIndex ].voice string = item.querySelector( ".string" ).value rate = item.querySelector( ".rate" ).value / 10 pitch = item.querySelector( ".pitch" ).value / 100 if string.length > 0 utterance = new SpeechSynthesisUtterance string utterance.voice = voice utterance.pitch = pitch utterance.rate = rate utterance.element = item @.utterances.push utterance @.root.player.run() words: => @.utterances = [] voices = speechSynthesis.getVoices() items = document.querySelectorAll ".words .slider .word" name = document.querySelector ".voice-name" voice = name[ name.selectedIndex ].voice for item in items string = item.querySelector( ".string" ).value rate = item.querySelector( ".rate" ).value / 10 pitch = item.querySelector( ".pitch" ).value / 100 item.querySelector( ".string" ).style.top = "#{100 - (10 + ( pitch / 2 * 80 ))}%" if string.length > 0 utterance = new SpeechSynthesisUtterance string utterance.voice = voice utterance.pitch = pitch utterance.rate = rate utterance.element = item @.utterances.push utterance @.root.player.run() class Player extends SubClass run: -> utterances = @.root.parse.utterances if utterances.length > 0 for utterance, index in utterances if index + 1 isnt utterances.length utterance.next = utterances[ index + 1 ] self = @ utterance.onend = -> @.element.classList.remove "playing" next = @.next self.speak next @.onend = undefined @.speak utterances[0] speak: ( utterance ) -> @.lastUtterance?.element.classList.remove "playing" @.lastUtterance = utterance @.lastUtterance.element.classList.add "playing" if @.lastUtterance.onend is null @.lastUtterance.onend = -> @.element.classList.remove "playing" window.speechSynthesis.speak utterance class Interface extends SubClass init: -> @.getElements() @.addListeners() getElements: -> @.playingButton = document.querySelector ".play-state" addListeners: -> @.playingButton.addEventListener "click" , => if @.playingButton.classList.contains "playing" # todo: pause else @.root.parse.words() setInterval => if window.speechSynthesis.speaking @.playingButton.classList.add "playing" else @.playingButton.classList.remove "playing" , 100 class Porting extends SubClass init: -> @.getElements() @.addListeners() getElements: -> @.importButton = document.querySelector "button.import" @.exportButton = document.querySelector "button.export" @.modal = document.querySelector "aside" @.closeButton = @.modal.querySelector ".close" addListeners: -> @.importButton.addEventListener "click" , => @.modal.classList.add "active" @.modal.classList.remove "exporting" @.modal.classList.add "importing" @.exportButton.addEventListener "click" , => @.modal.classList.add "active" @.modal.classList.remove "importing" @.modal.classList.add "exporting" @.closeButton.addEventListener "click" , => @.modal.classList.remove "active" class App constructor: -> @.words = new Words @ @.parse = new Parse @ @.player = new Player @ @.interface = new Interface @ @.porting = new Porting @ new App