Dojo chat widget example

The Dojo Toolkit provides a widget mechanism for HTML objects. In this example, a simple chat widget is examined. Refer to Dojo documentation for more information on widget creation and usage. This example is intended to illustrate publish and subscribe interactions within a widget to a server, through the Dojo-included cometd client. An instance of the example chat widget resembles the following example:

Example Chat Widget


Widget definition
dojo.provide("samples.widget.ChatWidget");
dojo.require("dojox.cometd");
dojo.require("dijit._Widget");
dojo.require("dijit._Templated");

dojo.declare("samples.widget.ChatWidget", [dijit._Widget, dijit._Templated], {
    templatePath: dojo.moduleUrl("samples", "widget/templates/ChatWidget.html"),
   
    title: "Chat",
    chatTopic:"",
    chatName:"",
  
    postCreate: function(){  
        dojox.cometd.subscribe(this.chatTopic,this, "receiveMessage");
        this.chatName = "User" +(Math.floor(Math.random()*10000) + 1);
        this.nameValue.value = this.chatName;
        this._appendText(this.titleText, this.title);
        dojox.cometd.publish(this.chatTopic, { user: this.chatName, operation:"new"});
    },
		
    receiveMessage: function(message){
        var chatarea = dojo.byId(this.chatBox);
        if (message.data.operation == "rename")
            chatarea.innerHTML = chatarea.innerHTML + "<br><i>" + message.data.oldUser + " has changed names to " + message.data.user + ".</i>";   
        else if (message.data.operation == "new")
            chatarea.innerHTML = chatarea.innerHTML + "<br><i>" + message.data.user + " has joined the chat.</i>";   
        else if (message.data.operation == "message")
            chatarea.innerHTML = chatarea.innerHTML + "<br><i>" + message.data.user + ":</i>&nbsp;&nbsp;" +  message.data.message;    
       chatarea.scrollTop = chatarea.scrollHeight;
    },
    
    sendMessage: function() {
       dojox.cometd.publish(this.chatTopic, {message: this.chatText.value, user: this.chatName, operation:"message"});
       this.chatText.value = ""; 
    }, 
       
    enterCheck: function(evt) {
        if(evt.keyCode == dojo.keys.ENTER) {
            this.sendMessage();
            dojo.stopEvent(evt);
        }
    },
    
    _appendText: function(node, text){
        while(node.firstChild){
	    node.removeChild(node.firstChild);
	}
        node.appendChild(document.createTextNode(text));
    },
     
    changeName: function() {  
        if (this.nameValue.value == "") {
            this.nameValue.value = this.chatName;   // Attempted to specify as blank. Revert to original name
            return;
       }
       if (this.nameValue.value == this.chatName)
           return;       
       dojox.cometd.publish(this.chatTopic, { user: this.nameValue.value, oldUser:this.chatName, operation:"rename"});   
       this.chatName = this.nameValue.value;
    }
});


The widget definition for the chat widget is not complex. Three properties exist for the widget: title, chatName, and chat topic. When the widget is created, the cometd client is used to subscribe to the server topic or chatTopic to receive chat messages from other clients. Cometd initialization occurs in the main HTML page where the chat widget is included. It is possible to call the cometd init function in the widget; however, that process is not done in this example. The reason for this is because other widgets might also need to be initialized, and it is easier to keep cometd initialization in the main HTML page. After cometd subscription, a random user name for identification is generated and stored in the chatName property, and a message is published indicating that a new person has entered the room. The HTML for the widget is specified with the templatePath variables. The contents of this file is listed later in this topic.

In the chat widget example, a different message is displayed when users enter the room, change their name, or write a message. A single topic is used to publish the three message types. The JavaScriptTM Object Notation (JSON) object parameter differentates the type of message to display in the receiveMessage function. The cometd subscribe function links server events that are published to the receiveMessage function of the widget. The receiveMessage function checks the operation type specified and writes the corresponding message to the chat box.


Widget HTML
    
<div class="chatContainer"> <span class="title" dojoAttachPoint="titleText"></span><br><br> <div dojoAttachPoint="chatBox" class="chatBox"></div> <div class="buttonArea"> <input dojoAttachPoint="chatText" dojoAttachEvent="onkeypress: enterCheck" type="text" class="inputBox" > <input dojoAttachEvent="onclick: sendMessage" type="button" value="Say" class="button" ><br> <input dojoAttachPoint="nameValue" type="text" style="width:90px;" value=""> <button class="button" dojoAttachEvent="onclick:changeName">Change name</button> </div> </div>
       


Widget CSS

.chatContainer {	
	width:320px;
	height:260px;
    border:1px solid black;
	padding-top:7px;
	padding-left:12px;
	text-align:center;
	background:#fff url("bg.jpg") repeat-x top left;
}

.chatBox {
	width:300px;
	height:160px;
	padding-left:5px;
	background-color:#FFFFFF;
	
	overflow:auto;
    text-align:left;
}

.buttonArea{ 
    padding-top:5px;
	padding-right:10px;
	text-align:right;
}

.button{ 
   font-size:84%;

}
	
.inputBox {
	width:260px;
}



The HTML excerpt outlines a chat box area for display of incoming messages, an input box and button to send chat messages, an input box and button to change names, and an outer container. HTML button events in the main widget definition are linked through the dojoAttachEvent function. Change the appearance of a widget by modifying the widget HTML, specifying a different template path, or specifying a different cascade style sheet (CSS) import in the main HTML page.

Main HTML page with widget definition
<html>	<head>
	<style type="text/css">
			@import "dojo/resources/dojo.css";
			@import "dijit/themes/tundra/tundra.css";
			@import "samples/widget/templates/ChatWidget.css";
	</style>

    <script language="JavaScript" src="dojo/dojo.js" djConfig="isDebug: false, parseOnLoad: true"></script>
    <script type="text/JavaScript" src="dojo/dojo.js"></script>	
    <script type="text/JavaScript">
       
        dojo.require("dojox.cometd");   
        dojo.registerModulePath("samples", "../samples");
        dojo.require("samples.widget.ChatWidget");
        dojo.require("dojo.parser");
        dojo.addOnLoad(function(){
            dojox.cometd.init("cometdTest");
        });
      </script>
</head><body>

 <div align="center">
 <br><br>
    <div
       dojoType="samples.widget.ChatWidget"
       title="Chat box #1"
       chatTopic="/chatTopic1">
    </div>   
  </div>
</body></html>
The main HTML page contains the widget instantiation. The chatTopic property and title are the parameters that are passed into widget creation. For this example, the chat name is a generated random name, but a chat name can also pass as a parameter for creation. Cometd initialization occurs after all Dojo initialization is complete. It is possible that the widgets subscribe to a topic before cometd initialization occurs; however, the cometd client stores these subscriptions for processing after initialization completes. The custom widget is found through the dojo.registerModulePath statement.