Coldfusion Websockets "User is typing..." Functionality

1.3k Views Asked by At

I'm playing around with Coldfusion 10's websockets and made a simple chat for testing. I've seen several chats where they have the "user is typing..." text that shows up when the other user is typing. Does anyone know how to implement this efficiently?

2

There are 2 best solutions below

0
On

Inside the Comments is a question on how to filter for one on one messaging. Here is some sample code for achieving this.

Instead of using the subscribeTo attribute, use the js function to subscribe the user and pass in some header values. These headers can then be used as filters on the publish call using selector

Example:

<cfwebsocket name="ChatSocket" onOpen="openHandler" onMessage="msgHandler" onError="errHandler">

<script>
    function openHandler(){
        //Subscribe to the channel, pass in headers for filtering later
        ChatSocket.subscribe('chatChannel',{name: '#Session.Auth.FirstName#', UserID: '#Session.Auth.UserID#', AccountID: '#Session.Auth.AccountID#' });
    }

    function publish(txt, userID){
        var msg = {
            AccountID: "#Session.Auth.AccountID#",
            publisher: '#Session.Auth.UserID#', 
            id: userID,
            message: converthtml(txt)
        };
        //When including headers, the "selector" is where you will filter who it goes to.
        var headers = {
            AccountID: "#Session.Auth.AccountID#",
            publisher: '#Session.Auth.UserID#', 
            id: userID,
            selector: "UserID eq '"+userID+"' and AccountID eq '#Session.Auth.AccountID#'"
        };
        ChatSocket.publish('chatChannel',msg, headers);

    }

    function msgHandler(message){
        console.log(message);
    }

    function errHandler(err){
        console.log(err);
    }
</script>
4
On

Create one more channel 'notification' and publish into it 'User is typing' when user does a 'keyDown' and 'emptystring' when 'keyUp'.

Subscribe to this channel along with you chat. the target of this channel on the receiver side shall be a whose inner html can be populated with 'User is Typing' message.

PseudoCode:

<cfwebsocket name="notificationSocket" 
             onmessage="notifyHandler"
             subscribeto="notificationChannel" >

<cfwebsocket name="ChatSocket" 
             onmessage="chatHandler"
             subscribeto="chatChannel" >

<!-- Conversation displayer -->
<div id="messageBoard"></div>

<!-- your text message input area -->
<textarea onKeyDown="sayTyping()" onKeyUp="sayStopped()" id="chatInput"></textarea>
<div id="notifyArea"></div>
<input name="submit" onClick="publishMessage()"></textarea>

<script>

    /*chat Functions*/
    var publishMessage = function(){
        var msg = document.getElementById('chatInput').value;
        mycfwebsocketobject.publish("chatChannel", msg );
    };

    var chatHandler = function(msgObj){
        document.getElementById('messageBoard').innerHTML += ColdFusion.JSON.encode(msgObj);
    };


    /*notifying Functions*/
    var notifyHandler = function(noteObj){
        document.getElementById('notifyArea').innerHTML = ColdFusion.JSON.encode(noteObj);
    };    

    var sayTyping = function(){
        mycfwebsocketobject.publish("notificationchannel","User is Typing..." );
    };
    var sayStopped = function(){
        mycfwebsocketobject.publish("notificationchannel","" );
    };

</script>

Another enhancement will be to have a div already with the text 'user is typing' and your channel broadcasts the text as 'show' and 'noshow'. This is basically the class name given to the to show and hide it. Less traffic.

Approach 2: Using the same channel

<cfwebsocket name="ChatSocket" 
             onmessage="chatHandler"
             subscribeto="chatChannel" >

<!-- Conversation displayer -->
<div id="messageBoard"></div>

<!-- your text message input area -->
<textarea onKeyDown="sayTyping()" onKeyUp="sayStopped()" id="chatInput"></textarea>
<div id="notifyArea" class="no">User is typing...</div>
<input name="submit" onClick="publishMessage()"></textarea>

<script>

    /*chat Functions*/
    var publishMessage = function(){
        var msg = document.getElementById('chatInput').value;
        mycfwebsocketobject.publish("chatChannel", msg );
    };

    var chatHandler = function(msgObj){
        var msg = ColdFusion.JSON.encode(msgObj);
        if (msg == '@userTyping@-yes'){
            notifyHandler('yes');
        }
        else if (msg == '@userTyping@-no'){
            notifyHandler('no');
        }
        else {
            document.getElementById('messageBoard').innerHTML += msg;
        }
    };


    /*notifying Functions*/
    var notifyHandler = function(action){

        document.getElementById('notifyArea').className = action;

        /*call the notify handler with off to stop showing the user is typing message
        after a certain interval of time. This is to avoid someone believing that 
        partner is still typing even when the connection is lost*/

        if(action == 'on'){
            setTimeout(function(){notifyHandler('no')},250);
        }
    };    

    var sayTyping = function(){
        mycfwebsocketobject.publish("chatChannel","@userTyping@-yes" );
    };
    var sayStopped = function(){
        mycfwebsocketobject.publish("chatChannel","@userTyping@-no" );
    };

</script>
<style>
.yes { display:block;}
.no { display:none;}
</style>

One can always trick this code by typing the message as '@userTyping@-yes' or '@userTyping@-no'. But as i said, this is just a POC. Also, for the timeout you have mentioned, the keyUp would take care of it anyway. But you can also call the notifyHandler() by a setTimeout() as shown above.