class SubClass
constructor: ( parent , data ) ->
@.root = parent.root or parent
@.parent = parent
@.init? data
class Words extends SubClass
template: "
Rate
Pitch
"
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