diff options
author | Stefan Radomski <radomski@tk.informatik.tu-darmstadt.de> | 2013-11-04 05:22:26 (GMT) |
---|---|---|
committer | Stefan Radomski <radomski@tk.informatik.tu-darmstadt.de> | 2013-11-04 05:22:26 (GMT) |
commit | 15a26b2e729a9f5326d6958e474d38a59a005f91 (patch) | |
tree | e34df4f19e164ac27fc0fe5c9d51ecb3316f8170 | |
parent | cb30bd1f44fcc3a0642a362afd4eaea0d8a7d199 (diff) | |
download | uscxml-15a26b2e729a9f5326d6958e474d38a59a005f91.zip uscxml-15a26b2e729a9f5326d6958e474d38a59a005f91.tar.gz uscxml-15a26b2e729a9f5326d6958e474d38a59a005f91.tar.bz2 |
Usability improvements for miles
-rw-r--r-- | apps/samples/miles/miles.js | 242 | ||||
-rw-r--r-- | apps/samples/miles/miles.scxml | 10 |
2 files changed, 194 insertions, 58 deletions
diff --git a/apps/samples/miles/miles.js b/apps/samples/miles/miles.js index a1d4422..cf7d729 100644 --- a/apps/samples/miles/miles.js +++ b/apps/samples/miles/miles.js @@ -43,6 +43,8 @@ function Miles(element, params) { participants: 1000 }; + var surpressPublication = false; // do not publish changes performed from subscriptions + var showVideo = true; var enableAudio = true; var stopChatScrolling = false; @@ -75,26 +77,46 @@ function Miles(element, params) { }, load: function(result) { self.connected = true; - // toggle connect button to disconnect self.connectDropDown.dropDown.onCancel(true); self.controlElem.replaceChild(self.controlDropDown.domNode, self.connectDropDown.domNode); + + showChat(); // trigger continuous updates - refreshImage(); - getChatText(); - getParticipants(); + refreshImage(); + getChatText(); + getParticipants(); } }); } this.disconnect = function() { self.connected = false; + hideChat(); self.controlDropDown.dropDown.onCancel(true); self.controlElem.replaceChild(self.connectDropDown.domNode, self.controlDropDown.domNode); } + var hideChat = function() { + // hide chat elements until connected + for(var key in self.chatElems) { + if (self.chatElems.hasOwnProperty(key) && "style" in self.chatElems[key]) + self.chatElems[key].style.display = "none"; + } + } + + var showChat = function() { + for(var key in self.chatElems) { + if (self.chatElems.hasOwnProperty(key) && "style" in self.chatElems[key]) + self.chatElems[key].style.display = ""; + } + } + var getParticipants = function() { + if (!self.connected) + return; + var query = ""; self.xhr.get({ // The URL to request @@ -102,24 +124,22 @@ function Miles(element, params) { handleAs:"json", error: function(err) { console.log(err); - if (self.connected) { - setTimeout(getParticipants, repollInterval.participants); - } + setTimeout(getParticipants, repollInterval.participants); }, load: function(result) { if (result.participants) { participants = result.participants; } - if (self.connected) { - console.log(participants); - setTimeout(getParticipants, repollInterval.participants); - } + setTimeout(getParticipants, repollInterval.participants); } }); } // fetch a base64 encoded image and set it as the src attribute var refreshImage = function() { + if (!self.connected) + return; + var query = ""; query += "?userid=" + encodeURIComponent(email); self.xhr.get({ @@ -131,30 +151,27 @@ function Miles(element, params) { }, error: function(err) { console.log(err); - if (self.connected) { - setTimeout(refreshImage, repollInterval.image); - } + setTimeout(refreshImage, repollInterval.image); }, load: function(result) { self.pictureElem.src = "data:image/jpeg;base64," + result; - if (self.connected) { - self.messageElem.innerHTML = self.imageIteration++; - setTimeout(refreshImage, repollInterval.image); - } + self.messageElem.innerHTML = self.imageIteration++; + setTimeout(refreshImage, repollInterval.image); } }); }; var getChatText = function() { + if (!self.connected) + return; + self.xhr.get({ // The URL to request url: "http://" + scxmlURL + "/miles/gettext", handleAs:"json", error: function(err) { console.log(err); - if (self.connected) { - setTimeout(getChatText, repollInterval.chat); - } + setTimeout(getChatText, repollInterval.chat); }, load: function(result) { if (result.message) { @@ -162,9 +179,7 @@ function Miles(element, params) { if (!stopChatScrolling) self.chatOutputElem.scrollTop = self.chatOutputElem.scrollHeight; } - if (self.connected) { - setTimeout(getChatText, repollInterval.chat); - } + setTimeout(getChatText, repollInterval.chat); } }); }; @@ -174,6 +189,7 @@ function Miles(element, params) { "dojo/_base/xhr", "dojo/dom", "dojo/on", + "dojo/topic", "dojo/_base/unload", "dijit/form/DropDownButton", "dijit/TooltipDialog", @@ -187,6 +203,7 @@ function Miles(element, params) { xhr, dom, on, + topic, baseUnload, DropDownButton, TooltipDialog, @@ -206,7 +223,7 @@ function Miles(element, params) { element.style.width = self.width + "px"; baseUnload.addOnWindowUnload(function(){ -// alert("unloading..."); + // have a call to close the session here }); // dynamically assemble the DOM we need @@ -227,7 +244,7 @@ function Miles(element, params) { <tr><td valign="top" colspan="2" >\ <div class="chatOutput" style="max-height:120px; overflow: auto">\ </td></tr>\ - <tr>\ + <tr class="chat">\ <td valign="top" style="vertical-align: middle">\ <div class="chatInput">\ </td>\ @@ -249,6 +266,10 @@ function Miles(element, params) { self.messageElem = dojo.query("div.messages", element)[0]; self.chatOutputElem = dojo.query("div.chatOutput", element)[0]; self.chatOutputElem.style.fontSize = "0.8em"; + self.chatElems = dojo.query(".chat", element); + + hideChat(); + on(self.chatOutputElem, "mouseover", function(evt) { stopChatScrolling = true; }); @@ -261,12 +282,14 @@ function Miles(element, params) { self.chatSendButton = new Button({ label: "Send", onClick: function(){ + alert(self.chatInput.value); self.xhr.post({ // The URL to request - url: "http://" + scxmlURL + "/miles/chat", - contentType: 'text/plain', + url: "http://" + scxmlURL + "/miles/text", + contentType: 'application/json', postData: dojo.toJson({ - message: chatInputElem.value + message: self.chatInput.value, + userid: email }), error: function(err) { console.log(err); @@ -314,13 +337,6 @@ function Miles(element, params) { }); dojo.query("div.email", self.connectToolTip.domNode)[0].appendChild(self.emailBox.domNode); - // self.remoteEmailBox = new TextBox({ - // name: "remoteEmail", - // value: remoteEmail, - // style: "width: 100%", - // }); - // dojo.query("div.remoteEmail", self.connectToolTip.domNode)[0].appendChild(self.remoteEmailBox.domNode); - self.reflectorIpBox = new TextBox({ name: "reflectorIp", value: reflectorIp, @@ -346,74 +362,190 @@ function Miles(element, params) { // Control parameters self.controlDropDownContent = domConst.toDom('\ <div>\ - <table>\ - <tr><td>Activate Camera:</td><td><div class="activateCamera" /></td></tr>\ - <tr><td style="padding-left: 1em">Compression:</td><td><div class="videoCompression" /></td></tr>\ - <tr><td style="padding-left: 1em">Framerate:</td><td><div class="videoFramerate" /></td></tr>\ - <tr><td style="padding-left: 1em">Width:</td><td><div class="videoWidth" /></td></tr>\ - <tr><td style="padding-left: 1em">Height:</td><td><div class="videoHeight" /></td></tr>\ - <tr><td>Open Microphone:</td><td><div class="openMicrophone" /></td></tr>\ - <tr><td style="padding-left: 1em">Encoding:</td><td><div class="audioEncoding" /></td></tr>\ - <tr><td colspan="2"><hr /></td></tr>\ - <tr><td>Enable Audio:</td><td><div class="enableAudio" /></td></tr>\ - <tr><td>Show Video:</td><td><div class="showVideo" /></td></tr>\ - <tr><td colspan="2"><hr /></td></tr>\ - <tr><td></td><td align="right"><div class="disconnectButton" /></td></tr>\ + <fieldset name="global">\ + <legend>Global Options</legend>\ + <table>\ + <tr><td>Activate Camera:</td><td><div class="activateCamera" /></td></tr>\ + <tr><td style="padding-left: 1em">Compression:</td><td><div class="videoCompression" /></td></tr>\ + <tr><td style="padding-left: 1em">Framerate:</td><td><div class="videoFramerate" /></td></tr>\ + <tr><td style="padding-left: 1em">Width:</td><td><div class="videoWidth" /></td></tr>\ + <tr><td style="padding-left: 1em">Height:</td><td><div class="videoHeight" /></td></tr>\ + <tr><td>Open Microphone:</td><td><div class="openMicrophone" /></td></tr>\ + <tr><td style="padding-left: 1em">Encoding:</td><td><div class="audioEncoding" /></td></tr>\ + </table>\ + </fieldset>\ + <fieldset name="session">\ + <legend>Session Options</legend>\ + <table>\ + <tr><td>Enable Audio:</td><td><div class="enableAudio" /></td></tr>\ + <tr><td>Show Video:</td><td><div class="showVideo" /></td></tr>\ + <tr><td></td><td align="right"><div class="disconnectButton" /></td></tr>\ + </table>\ + </fieldset>\ </div>\ '); self.controlToolTip = new TooltipDialog({ content:self.controlDropDownContent, style:"max-height:320px"}); self.controlDropDown = new DropDownButton({ label: "Session", dropDown: self.controlToolTip }); // Control parameters + + // global camera + topic.subscribe("miles/activateCamera", function(data) { + surpressPublication = true; + self.activateCameraCheckbox.set('value', data.activateCamera); + self.videoCompressionSelect.set('value', data.videoCompression); + self.videoFramerateSpinner.set('value', data.videoFramerate); + self.videoWidthSpinner.set('value', data.videoWidth); + self.videoHeightSpinner.set('value', data.videoHeight); + surpressPublication = false; + }); + + var publishCameraParameters = function() { + topic.publish("miles/activateCamera", { + "activateCamera": activateCamera, + "videoCompression": videoCompression, + "videoFramerate": videoFramerate, + "videoWidth": videoWidth, + "videoHeight": videoHeight + }); + // tell the server + if (activateCamera) { + var query = ""; + query += "?width=" + encodeURIComponent(videoWidth); + query += "&height=" + encodeURIComponent(videoHeight); + query += "&framerate=" + encodeURIComponent(videoFramerate); + query += "&compression=" + encodeURIComponent(videoCompression); + self.xhr.get({ + url: "http://" + scxmlURL + "/miles/sendvideo" + query, + error: function(err) { + console.log(err); + } + }); + } else { + self.xhr.get({ + url: "http://" + scxmlURL + "/miles/sendvideooff", + error: function(err) { + console.log(err); + } + }); + } + }; + self.activateCameraCheckbox = new CheckBox({ name: "activateCamera", - value: activateCamera, checked: activateCamera, + onChange: function() { + activateCamera = self.activateCameraCheckbox.get('value'); + if (!surpressPublication) + publishCameraParameters(); + } }); dojo.query("div.activateCamera", self.controlToolTip.domNode)[0].appendChild(self.activateCameraCheckbox.domNode); self.videoCompressionSelect = new Select({ name: "videoCompression", - value: videoCompression, options: videoCompressions, + onChange: function() { + videoCompression = self.videoCompressionSelect.get('value'); + if (!surpressPublication) + publishCameraParameters(); + } }); dojo.query("div.videoCompression", self.controlToolTip.domNode)[0].appendChild(self.videoCompressionSelect.domNode); self.videoFramerateSpinner = new NumberSpinner({ name: "videoFramerate", value: videoFramerate, - style: "width: 50px" + style: "width: 50px", + onChange: function() { + videoFramerate = self.videoFramerateSpinner.get('value'); + if (!surpressPublication) + publishCameraParameters(); + } }); dojo.query("div.videoFramerate", self.controlToolTip.domNode)[0].appendChild(self.videoFramerateSpinner.domNode); self.videoWidthSpinner = new NumberSpinner({ name: "videoWidth", value: videoWidth, - style: "width: 50px" + style: "width: 50px", + onChange: function() { + videoWidth = self.videoWidthSpinner.get('value'); + if (!surpressPublication) + publishCameraParameters(); + } }); dojo.query("div.videoWidth", self.controlToolTip.domNode)[0].appendChild(self.videoWidthSpinner.domNode); self.videoHeightSpinner = new NumberSpinner({ name: "videoHeight", value: videoHeight, - style: "width: 50px" + style: "width: 50px", + onChange: function() { + videoHeight = self.videoHeightSpinner.get('value'); + if (!surpressPublication) + publishCameraParameters(); + } }); dojo.query("div.videoHeight", self.controlToolTip.domNode)[0].appendChild(self.videoHeightSpinner.domNode); + // global microphone + topic.subscribe("miles/openMicrophone", function(data) { + surpressPublication = true; + self.openMicrophoneCheckbox.set('value', data.openMicrophone); + self.audioEncodingSelect.set('value', data.audioEncoding); + surpressPublication = false; + }); + + var publishMicrophoneParameters = function() { + topic.publish("miles/openMicrophone", { + "openMicrophone": openMicrophone, + "audioEncoding": audioEncoding + }); + // tell the server + if (openMicrophone) { + var query = ""; + query += "?encoding=" + encodeURIComponent(audioEncoding); + self.xhr.get({ + url: "http://" + scxmlURL + "/miles/sendaudio" + query, + error: function(err) { + console.log(err); + } + }); + } else { + self.xhr.get({ + url: "http://" + scxmlURL + "/miles/sendaudiooff", + error: function(err) { + console.log(err); + } + }); + } + } + self.openMicrophoneCheckbox = new CheckBox({ name: "openMicrophone", value: openMicrophone, checked: openMicrophone, + onChange: function() { + openMicrophone = self.openMicrophoneCheckbox.get('value'); + if (!surpressPublication) + publishMicrophoneParameters(); + } }); dojo.query("div.openMicrophone", self.controlToolTip.domNode)[0].appendChild(self.openMicrophoneCheckbox.domNode); self.audioEncodingSelect = new Select({ name: "audioEncoding", - value: audioEncoding, options: audioEncodings, + onChange: function() { + audioEncoding = self.audioEncodingSelect.get('value'); + if (!surpressPublication) + publishMicrophoneParameters(); + } }); dojo.query("div.audioEncoding", self.controlToolTip.domNode)[0].appendChild(self.audioEncodingSelect.domNode); + // session scoped parameters self.enableAudioCheckbox = new CheckBox({ name: "enableAudio", diff --git a/apps/samples/miles/miles.scxml b/apps/samples/miles/miles.scxml index 9b1426a..9e486b4 100644 --- a/apps/samples/miles/miles.scxml +++ b/apps/samples/miles/miles.scxml @@ -3,6 +3,7 @@ <state id="main"> <invoke type="miles" id="miles"> <finalize> + <log label="out" expr="_event.name" /> <script>//dump(_event);</script> <if cond="_event.data.origin"> <!-- <log label="Reply-length" expr="_event.data.base64.length" /> --> @@ -37,6 +38,7 @@ </transition> <transition event="http.get" target="idle"> + <log label="in" expr="_event.data.path" /> <script>//dump(_event);</script> <if cond="false"> @@ -116,6 +118,7 @@ <!-- SEND AUDIO OFF ############### --> <elseif cond="_event.data.pathComponent[1] === 'sendaudiooff'" /> <send target="#_miles" event="sendaudiooff"> + <param name="origin" expr="_event.origin" /> </send> <!-- GET TEXT ############### --> @@ -130,15 +133,16 @@ </transition> <transition event="http.post" target="idle"> - <script>//dump(_event);</script> + <log label="in" expr="_event.data.path" /> + <script>dump(_event);</script> <if cond="false"> <!-- POST TEXT ############### --> <elseif cond="_event.data.pathComponent[1] === 'text'" /> <send target="#_miles" event="posttext"> <param name="origin" expr="_event.origin" /> - <param name="userid" expr="_event.data.query.userid" /> - <param name="message" expr="_event.data.content" /> + <param name="userid" expr="_event.data.content.userid" /> + <param name="message" expr="_event.data.content.message" /> </send> <else /> |