/** * HTML speech/sound for a Spaceship! game HTML model. * * Copyright (c) 2008, 2009 Peter Parente under the terms of the BSD license. * http://creativecommons.org/licenses/BSD/ */ dojo.provide('spaceship.html.HtmlAudio'); dojo.require('dijit._Widget'); dojo.require('spaceship.html.HtmlTopics'); dojo.require('spaceship.sounds.AudioManager'); dojo.require('spaceship.utils.Subscriber'); // @todo: factor out html controller dojo.declare('spaceship.html.HtmlAudio', [dijit._Widget, spaceship.utils.Subscriber], { // html model model: null, // audio manager audio: spaceship.sounds.AudioManager, /** * Called after widget construction. */ postMixInProperties: function() { // audio subscription token this._token = null; // start reading text continuously right away this._continuous = true; }, /** * Called after widget creation. Subscribes to HTML topics. */ postCreate : function() { // subscribe to html topics this.subscribe(spaceship.html.END_HTML_TOPIC, 'onEndHtml'); this.subscribe(spaceship.html.LOAD_HTML_TOPIC, 'onLoadHtml'); this.subscribe(spaceship.html.REGARD_HTML_TOPIC, 'onRegardHtml'); // listen for end of chunk speech events this._token = this.audio.addObserver(dojo.hitch(this, this.onSayDone), spaceship.sounds.SPEECH_CHANNEL, ['finished-say', 'error']); // check if we have an initial regard to render var por = this.model.getCurrentRegard(); if(por) { this.onRegardHtml(por); } }, /** * Called after widget cleanup. Unsubscribes from all topics. */ uninitialize: function() { this.audio.removeObserver(this._token); this.unsubscribeAll(); }, /** * Called when the HTML model is destroying. Destroys this widget. * * @subscribe END_HTML_TOPIC */ onEndHtml: function() { this.destroyRecursive(); }, /** * Called when the HTML model has a new DOM. * * @subscribe LOAD_HTML_TOPIC */ onLoadHtml: function() { var node = this.model.getDOM(); if(node.parentNode) { this.connect(node.parentNode, 'onkeypress', 'onKeyPress'); } }, /** * Called when the point of regard is moved to a different chunk in the * HTML model. * * @param node DOM node under regard. * @subscribe REGARD_HTML_TOPIC */ onRegardHtml: function(node) { this.audio.stop(spaceship.sounds.SPEECH_CHANNEL); this.audio.say(node.textContent, spaceship.sounds.SPEECH_CHANNEL, 'chunk'); }, /** * Called when the text of the current regard is finished being said. * * @param audio Audio manager * @param response Audio response object */ onSayDone: function(audio, response) { if(this._continuous && response.name == 'chunk') { // regard the next chunk this.model.regardNextChunk(); } }, /** * Called when the user presses a key. * * @param event Event object */ onKeyPress: function(event) { // get the appropriate code for the key var code = event.charCode || event.keyCode; switch(code) { case dojo.keys.SPACE: case dojo.keys.ENTER: // read continuously starting with the current chunk var por = this.model.getCurrentRegard(); if(por) { this._continuous = true; this.onRegardHtml(por); } dojo.stopEvent(event); break; default: // reset continuous flag this._continuous = false; } } });