Return-Path: Delivered-To: apmail-activemq-commits-archive@www.apache.org Received: (qmail 57932 invoked from network); 19 Apr 2010 15:28:07 -0000 Received: from unknown (HELO mail.apache.org) (140.211.11.3) by 140.211.11.9 with SMTP; 19 Apr 2010 15:28:07 -0000 Received: (qmail 42529 invoked by uid 500); 19 Apr 2010 15:28:07 -0000 Delivered-To: apmail-activemq-commits-archive@activemq.apache.org Received: (qmail 42473 invoked by uid 500); 19 Apr 2010 15:28:07 -0000 Mailing-List: contact commits-help@activemq.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@activemq.apache.org Delivered-To: mailing list commits@activemq.apache.org Received: (qmail 42466 invoked by uid 99); 19 Apr 2010 15:28:07 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 19 Apr 2010 15:28:07 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 19 Apr 2010 15:28:00 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 4C75C23888DD; Mon, 19 Apr 2010 15:27:16 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r935623 [1/5] - in /activemq/trunk/activemq-web-demo/src/main/webapp: ./ js/ Date: Mon, 19 Apr 2010 15:27:16 -0000 To: commits@activemq.apache.org From: dejanb@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20100419152716.4C75C23888DD@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: dejanb Date: Mon Apr 19 15:27:15 2010 New Revision: 935623 URL: http://svn.apache.org/viewvc?rev=935623&view=rev Log: https://issues.apache.org/activemq/browse/AMQ-1377 - Ajax client refactoring Added: activemq/trunk/activemq-web-demo/src/main/webapp/js/amq.js activemq/trunk/activemq-web-demo/src/main/webapp/js/amq_dojo_adapter.js activemq/trunk/activemq-web-demo/src/main/webapp/js/amq_jquery_adapter.js (with props) activemq/trunk/activemq-web-demo/src/main/webapp/js/amq_prototype_adapter.js (with props) activemq/trunk/activemq-web-demo/src/main/webapp/js/chat.js (with props) activemq/trunk/activemq-web-demo/src/main/webapp/js/dojo.js activemq/trunk/activemq-web-demo/src/main/webapp/js/jquery-1.4.2.min.js activemq/trunk/activemq-web-demo/src/main/webapp/js/prototype.js (with props) Removed: activemq/trunk/activemq-web-demo/src/main/webapp/chat.js activemq/trunk/activemq-web-demo/src/main/webapp/js/scriptaculous.js Modified: activemq/trunk/activemq-web-demo/src/main/webapp/chat.css activemq/trunk/activemq-web-demo/src/main/webapp/chat.html Modified: activemq/trunk/activemq-web-demo/src/main/webapp/chat.css URL: http://svn.apache.org/viewvc/activemq/trunk/activemq-web-demo/src/main/webapp/chat.css?rev=935623&r1=935622&r2=935623&view=diff ============================================================================== --- activemq/trunk/activemq-web-demo/src/main/webapp/chat.css (original) +++ activemq/trunk/activemq-web-demo/src/main/webapp/chat.css Mon Apr 19 15:27:15 2010 @@ -16,7 +16,7 @@ */ div#chatroom { - width: 41em; + width: 81em; background-color: #e0e0e0; border: 1px solid black; } @@ -24,8 +24,8 @@ div#chatroom div#chat { float: left; - width: 30em; - height: 20ex; + width: 60em; + height: 40ex; overflow: auto; background-color: #f0f0f0; padding: 4px; @@ -36,7 +36,7 @@ div#members { float: left; clear: right; - width: 10em; + width: 20em; border: 0px solid black; } Modified: activemq/trunk/activemq-web-demo/src/main/webapp/chat.html URL: http://svn.apache.org/viewvc/activemq/trunk/activemq-web-demo/src/main/webapp/chat.html?rev=935623&r1=935622&r2=935623&view=diff ============================================================================== --- activemq/trunk/activemq-web-demo/src/main/webapp/chat.html (original) +++ activemq/trunk/activemq-web-demo/src/main/webapp/chat.html Mon Apr 19 15:27:15 2010 @@ -1,35 +1,114 @@ - - -Chat - - - - - - - + + + + + + + + + + + + + Chat Example - ActiveMQ Web Demos + + + + + + + + + + + + + + + + + +
+
+
+
+
+
+
+
+
+
+ +
+ + + + + +
+ + +
+ + + + + + + + +
+

Chat Example

-Welcome to this little chat example -
-
+

Welcome to the Ajax chat example

@@ -37,15 +116,104 @@ Welcome to this little chat example
-
- - +

+ This Chat example creates an ActiveMQ broker using the configuration + information found in the web.xml file. There isn't much there. + Just a name-value parameter named org.apache.activemq.brokerURL + is assigned a value of vm://localhost?broker.persistent=false. + This is enough however to lazy-initialize the broker when it is needed. +

+

+ The client leverages a javascript library amq.js to perform all + of the JMS-related client side code. This involves establishing a + communication pipeline to the JMS server. This pipeline uses a long-poll + connection to the server. All JMS communication will be received down this + pipe, and when the JMS server has no traffic to send, this pipeline will + patiently wait until there is new traffic or until it times out. If a + timeout does occur, the connection will reconnect to the server for another + round. (Of course you will want/need to use a server that supports + continuations in order for this to scale beyond a few hundred clients.) +

+

+ The chat.js file contains the script to respond to the UI + interactions. It also talks to the amq.js file to send messages + and provides a message handler that will respond to incoming JMS messages. +

+

+ There is no server-side state in this application. The client sets up a JMS + Topic on the server and attaches itself as a listener to this topic. From + that point, all messages that are sent to the topic are received by each + listener. Even the list of members in the chat room are the result of + clients replying to a ping request. +

+

+ Please note that amq.js has been refactored to allow AJAX calls + to be made using any javascript library. Example adapter classes for jQuery + and Prototype have been provided. +

+ + +
+
+ + +
+ + +
+
+
+
+
+
+ +
+
+ + + + Added: activemq/trunk/activemq-web-demo/src/main/webapp/js/amq.js URL: http://svn.apache.org/viewvc/activemq/trunk/activemq-web-demo/src/main/webapp/js/amq.js?rev=935623&view=auto ============================================================================== --- activemq/trunk/activemq-web-demo/src/main/webapp/js/amq.js (added) +++ activemq/trunk/activemq-web-demo/src/main/webapp/js/amq.js Mon Apr 19 15:27:15 2010 @@ -0,0 +1,232 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// AMQ Ajax handler +// This class provides the main API for using the Ajax features of AMQ. It +// allows JMS messages to be sent and received from javascript when used +// with the org.apache.activemq.web.MessageListenerServlet. +// +// This version of the file provides an adapter interface for the jquery library +// and a namespace for the Javascript file, private/public variables and +// methods, and other scripting niceties. -- jim cook 2007/08/28 + +var org = org || {}; +org.activemq = org.activemq || {}; + +org.activemq.Amq = function() { + var connectStatusHandler; + + // Just a shortcut to eliminate some redundant typing. + var adapter = org.activemq.AmqAdapter; + + if (typeof adapter == 'undefined') { + throw 'An org.activemq.AmqAdapter must be declared before the amq.js script file.' + } + + // The URI of the AjaxServlet. + var uri; + + // The number of seconds that the long-polling socket will stay connected. + // Best to keep this to a value less than one minute. + var timeout; + + // Poll delay. if set to positive integer, this is the time to wait in ms + // before sending the next poll after the last completes. + var pollDelay; + + // Inidicates whether logging is active or not. Not by default. + var logging = false; + + // 5 second delay if an error occurs during poll. This could be due to + // server capacity problems or a timeout condition. + var pollErrorDelay = 5000; + + // Map of handlers that will respond to message receipts. The id used during + // addListener(id, destination, handler) is used to key the callback + // handler. + var messageHandlers = {}; + + // Indicates whether an AJAX post call is in progress. + var batchInProgress = false; + + // A collection of pending messages that accumulate when an AJAX call is in + // progress. These messages will be delivered as soon as the current call + // completes. The array contains objects in the format { destination, + // message, messageType }. + var messageQueue = []; + + /** + * Iterate over the returned XML and for each message in the response, + * invoke the handler with the matching id. + */ + var messageHandler = function(data) { + var response = data.getElementsByTagName("ajax-response"); + if (response != null && response.length == 1) { + connectStatusHandler(true); + var responses = response[0].childNodes; // + for (var i = 0; i < responses.length; i++) { + var responseElement = responses[i]; + + // only process nodes of type element..... + if (responseElement.nodeType != 1) continue; + + var id = responseElement.getAttribute('id'); + + var handler = messageHandlers[id]; + + if (logging && handler == null) { + adapter.log('No handler found to match message with id = ' + id); + continue; + } + + // Loop thru and handle each + for (var j = 0; j < responseElement.childNodes.length; j++) { + handler(responseElement.childNodes[j]); + } + } + } + }; + + var errorHandler = function(xhr, status, ex) { + connectStatusHandler(false); + if (logging) adapter.log('Error occurred in ajax call. HTTP result: ' + + xhr.status + ', status: ' + status); + } + + var pollErrorHandler = function(xhr, status, ex) { + connectStatusHandler(false); + if (status === 'error' && xhr.status === 0) { + if (logging) adapter.log('Server connection dropped.'); + setTimeout(function() { sendPoll(); }, pollErrorDelay); + return; + } + if (logging) adapter.log('Error occurred in poll. HTTP result: ' + + xhr.status + ', status: ' + status); + setTimeout(function() { sendPoll(); }, pollErrorDelay); + } + + var pollHandler = function(data) { + try { + messageHandler(data); + } catch(e) { + if (logging) adapter.log('Exception in the poll handler: ' + data, e); + throw(e); + } finally { + setTimeout(sendPoll, pollDelay); + } + }; + + var sendPoll = function() { + // Workaround IE6 bug where it caches the response + // Generate a unique query string with date and random + var now = new Date(); + var data = 'timeout=' + timeout * 1000 + + '&d=' + now.getTime() + + '&r=' + Math.random(); + + var options = { method: 'get', + data: data, + success: pollHandler, + error: pollErrorHandler}; + adapter.ajax(uri, options); + }; + + var sendJmsMessage = function(destination, message, type) { + // Add message to outbound queue + if (batchInProgress) { + messageQueue[messageQueue.length] = { + destination: destination, + message: message, + messageType: type + }; + } else { + org.activemq.Amq.startBatch(); + adapter.ajax(uri, { method: 'post', + data: 'destination=' + destination + '&message=' + message + '&type=' + type, + error: errorHandler, + success: org.activemq.Amq.endBatch}); + } + }; + + var buildParams = function(msgs) { + var s = []; + for (var i = 0, c = msgs.length; i < c; i++) { + if (i != 0) s[s.length] = '&'; + s[s.length] = ((i == 0) ? 'destination' : 'd' + i); + s[s.length] = '='; + s[s.length] = msgs[i].destination; + s[s.length] = ((i == 0) ? '&message' : '&m' + i); + s[s.length] = '='; + s[s.length] = msgs[i].message; + s[s.length] = ((i == 0) ? '&type' : '&t' + i); + s[s.length] = '='; + s[s.length] = msgs[i].messageType; + } + return s.join(''); + } + + return { + init : function(options) { + connectStatusHandler = options.connectStatusHandler || function(connected){}; + uri = options.uri || '/amq'; + pollDelay = typeof options.pollDelay == 'number' ? options.pollDelay : 0; + timeout = typeof options.timeout == 'number' ? options.timeout : 25; + logging = options.logging; + adapter.init(options); + sendPoll(); + }, + + startBatch : function() { + batchInProgress = true; + }, + + endBatch : function() { + if (messageQueue.length > 0) { + var body = buildParams(messageQueue); + messageQueue.length = 0; + org.activemq.Amq.startBatch(); + adapter.ajax(uri, { + method: 'post', + data: body, + success: org.activemq.Amq.endBatch, + error: errorHandler}); + } else { + batchInProgress = false; + } + }, + + // Send a JMS message to a destination (eg topic://MY.TOPIC). Message + // should be xml or encoded xml content. + sendMessage : function(destination, message) { + sendJmsMessage(destination, message, 'send'); + }, + + // Listen on a channel or topic. + // handler must be a function taking a message argument + addListener : function(id, destination, handler) { + messageHandlers[id] = handler; + sendJmsMessage(destination, id, 'listen'); + }, + + // remove Listener from channel or topic. + removeListener : function(id, destination) { + messageHandlers[id] = null; + sendJmsMessage(destination, id, 'unlisten'); + } + }; +}(); Added: activemq/trunk/activemq-web-demo/src/main/webapp/js/amq_dojo_adapter.js URL: http://svn.apache.org/viewvc/activemq/trunk/activemq-web-demo/src/main/webapp/js/amq_dojo_adapter.js?rev=935623&view=auto ============================================================================== --- activemq/trunk/activemq-web-demo/src/main/webapp/js/amq_dojo_adapter.js (added) +++ activemq/trunk/activemq-web-demo/src/main/webapp/js/amq_dojo_adapter.js Mon Apr 19 15:27:15 2010 @@ -0,0 +1,80 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// AMQ Ajax Adapter for Dojo +// This class provides an adapter interface for the Dojo library to perform +// some of the library-dependent tasks...namely logging and ajax. + +var org = org || {}; +org.activemq = org.activemq || {}; + +org.activemq.AmqAdapter = { + + init: function(options) { + }, + +/** + * Implement this method to make an AJAX call to the AjaxServlet. An + * options object will accompany this class and will contain the properties + * that describe the details of the AJAX call. The options object will + * have the following properties: + * + * - method: 'get' or 'post' + * - data: query data to accompany the post or get. + * - success: A callback function that is invoked upon successful + * completion of the AJAX call. The parameter is: + * - data: The result of the AJAX call. In the case of XML + * data should resolve to a Document element. + * - error: A callback when some type of error occurs. The callback + * function's parameters should be: + * - xhr: The XmlHttpRequest object. + * - status: A text string of the status. + * - ex: The exception that caused the error. + */ + ajax: function(uri, options) { + if (options.method == 'post') { + dojo.xhrPost({ + url: uri, + handleAs: "xml", + postData: options.data, + load : options.success ? options.success : function() {}, + error: options.error ? function(ex, ioargs) { + options.error(ioargs.xhr,ioargs.xhr.status, ex); + } : function() {} + }); + } else { + if (options.data) + { + uri += "?"; + uri += options.data; + } + dojo.xhrGet({ + url: uri, + handleAs: "xml", + load : options.success ? options.success : function() {}, + error: options.error ? function(ex, ioargs) { + options.error(ioargs.xhr,ioargs.xhr.status, ex); + } : function() {} + }); + } + }, + + log: function(message, exception) { + if (typeof console != 'undefined' && console.log) console.log(message); + } +}; Added: activemq/trunk/activemq-web-demo/src/main/webapp/js/amq_jquery_adapter.js URL: http://svn.apache.org/viewvc/activemq/trunk/activemq-web-demo/src/main/webapp/js/amq_jquery_adapter.js?rev=935623&view=auto ============================================================================== --- activemq/trunk/activemq-web-demo/src/main/webapp/js/amq_jquery_adapter.js (added) +++ activemq/trunk/activemq-web-demo/src/main/webapp/js/amq_jquery_adapter.js Mon Apr 19 15:27:15 2010 @@ -0,0 +1,80 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// AMQ Ajax Adapter for jQuery +// This class provides an adapter interface for the jquery library to perform +// some of the library-dependent tasks...namely logging and ajax. + +var org = org || {}; +org.activemq = org.activemq || {}; + +org.activemq.AmqAdapter = { + + init: function(options) { + }, + + /** + * Implement this method to make an AJAX call to the AjaxServlet. An + * options object will accompany this class and will contain the properties + * that describe the details of the AJAX call. The options object will + * have the following properties: + * + * - method: 'get' or 'post' + * - data: query data to accompany the post or get. + * - success: A callback function that is invoked upon successful + * completion of the AJAX call. The parameter is: + * - data: The result of the AJAX call. In the case of XML + * data should resolve to a Document element. + * - error: A callback when some type of error occurs. The callback + * function's parameters should be: + * - xhr: The XmlHttpRequest object. + * - status: A text string of the status. + * - ex: The exception that caused the error. + */ + ajax: function(uri, options) { + if (options.method == 'post') { + jQuery.ajax({ + type: "POST", + url: uri, + data: options.data, + success: options.success || function(){}, + error: options.error || function(){}, + beforeSend: function(xhr) { + /* Force "Connection: close" for Mozilla browsers to work around + * a bug where XMLHttpReqeuest sends an incorrect Content-length + * header. See Mozilla Bugzilla #246651. + */ + xhr.setRequestHeader("Connection", 'close'); + } + }); + } else { + jQuery.ajax({ + type: "GET", + url: uri, + data: options.data, + success: options.success || function(){}, + error: options.error || function(){}, + dataType: 'xml' + }); + } + }, + + log: function(message, exception) { + if (typeof console != 'undefined' && console.log) console.log(message); + } +}; Propchange: activemq/trunk/activemq-web-demo/src/main/webapp/js/amq_jquery_adapter.js ------------------------------------------------------------------------------ svn:executable = * Added: activemq/trunk/activemq-web-demo/src/main/webapp/js/amq_prototype_adapter.js URL: http://svn.apache.org/viewvc/activemq/trunk/activemq-web-demo/src/main/webapp/js/amq_prototype_adapter.js?rev=935623&view=auto ============================================================================== --- activemq/trunk/activemq-web-demo/src/main/webapp/js/amq_prototype_adapter.js (added) +++ activemq/trunk/activemq-web-demo/src/main/webapp/js/amq_prototype_adapter.js Mon Apr 19 15:27:15 2010 @@ -0,0 +1,90 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// AMQ Ajax Adapter for Prototype +// This class provides an adapter interface for the prototype library to perform +// some of the library-dependent tasks...namely logging and ajax. + +var org = org || {}; +org.activemq = org.activemq || {}; + +org.activemq.AmqAdapter = { + + init: function(options) { + }, + +/** + * Implement this method to make an AJAX call to the AjaxServlet. An + * options object will accompany this class and will contain the properties + * that describe the details of the AJAX call. The options object will + * have the following properties: + * + * - method: 'get' or 'post' + * - data: query data to accompany the post or get. + * - success: A callback function that is invoked upon successful + * completion of the AJAX call. The parameter is: + * - data: The result of the AJAX call. In the case of XML + * data should resolve to a Document element. + * - error: A callback when some type of error occurs. The callback + * function's parameters should be: + * - xhr: The XmlHttpRequest object. + * - status: A text string of the status. + * - ex: The exception that caused the error. + */ + ajax: function(uri, options) { + if (options.method == 'post') { + new Ajax.Request(uri, { + method: "post", + postBody: options.data, + onSuccess: options.success ? function(xhr, header) { + if (options.success) { + var ct = xhr.getResponseHeader("content-type"); + var xml = ct && ct.indexOf("xml") >= 0; + var data = xml ? xhr.responseXML : xhr.responseText; + options.success(data); + } + } : function() {}, + onFailure: options.error || function() { + }, + onException: options.error || function() { + } + }); + } else { + new Ajax.Request(uri, { + method: "get", + parameters: options.data, + onSuccess: function(xhr, header) { + if (options.success) { + var ct = xhr.getResponseHeader("content-type"); + var xml = ct && ct.indexOf("xml") >= 0; + var data = xml ? xhr.responseXML : xhr.responseText; + options.success(data); + } + }, + onFailure: options.error || function() { + }, + onException: options.error || function() { + } + }); + } + }, + + log: function(message, exception) { + if (typeof console != 'undefined' && console.log) console.log(message); + } +}; Propchange: activemq/trunk/activemq-web-demo/src/main/webapp/js/amq_prototype_adapter.js ------------------------------------------------------------------------------ svn:executable = * Added: activemq/trunk/activemq-web-demo/src/main/webapp/js/chat.js URL: http://svn.apache.org/viewvc/activemq/trunk/activemq-web-demo/src/main/webapp/js/chat.js?rev=935623&view=auto ============================================================================== --- activemq/trunk/activemq-web-demo/src/main/webapp/js/chat.js (added) +++ activemq/trunk/activemq-web-demo/src/main/webapp/js/chat.js Mon Apr 19 15:27:15 2010 @@ -0,0 +1,213 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the 'License'); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var amq = org.activemq.Amq; + +org.activemq.Chat = function() { + var last = ''; + + var user = null; + + var chatTopic = 'topic://CHAT.DEMO'; + + var chat, join, joined, phrase, members, username = null; + + var chatHandler = function(message) { + var type = message.getAttribute('type'); + var from = message.getAttribute('from'); + + switch (type) { + // Incoming chat message + case 'chat' : { + var text = message.childNodes[0].data; + + if (from == last) from = '...'; + else { + last = from; + from += ':'; + } + + chat.innerHTML += '' + from + ' ' + text + '
'; + break; + } + + // Incoming ping request, add the person's name to your list. + case 'ping' : { + members.innerHTML += '' + from + '
'; + break; + } + + // someone new joined the chatroom, clear your list and + // broadcast your name to all users. + case 'join' : { + members.innerHTML = ''; + if (user != null) + amq.sendMessage(chatTopic, ''); + chat.innerHTML += '' + from + ' has joined the room!
'; + break; + } + + // Screw you guys, I'm going home... + // When I (and everyone else) receive a leave message, we broadcast + // our own names in a ping in order to update everyone's list. + // todo: Make this more efficient by simply removing the person's name from the list. + case 'leave': { + members.innerHTML = ''; + chat.innerHTML += '' + from + ' has left the room!
'; + + // If we are the one that is leaving... + if (from == user) { + // switch the input form + join.className = ''; + joined.className = 'hidden'; + username.focus(); + + user = null; + amq.removeListener('chat', chatTopic); + } + if (user != null) + amq.sendMessage(chatTopic, ''); + break; + } + } + + chat.scrollTop = chat.scrollHeight - chat.clientHeight; + }; + + var getKeyCode = function (ev) { + var keyc; + if (window.event) keyc = window.event.keyCode; + else keyc = ev.keyCode; + return keyc; + }; + + // Again, you would generally use your particular js library to attach + // event handlers. However, I wanted to remove the dependency on the + // behaviors.js file in the original code, and I am demonstrating a library + // that can work with a variety of js libraries, so we are going old-school. + var addEvent = function(obj, type, fn) { + if (obj.addEventListener) + obj.addEventListener(type, fn, false); + else if (obj.attachEvent) { + obj["e"+type+fn] = fn; + obj[type+fn] = function() { obj["e"+type+fn]( window.event ); } + obj.attachEvent( "on"+type, obj[type+fn] ); + } + }; + + var initEventHandlers = function() { + addEvent(username, 'keyup', function(ev) { + var keyc = getKeyCode(ev); + if (keyc == 13 || keyc == 10) { + org.activemq.Chat.join(); + return false; + } + return true; + }); + + addEvent(document.getElementById('joinB'), 'click', function() { + org.activemq.Chat.join(); + return true; + }); + + addEvent(phrase, 'keyup', function(ev) { + var keyc = getKeyCode(ev); + + if (keyc == 13 || keyc == 10) { + var text = phrase.value; + phrase.value = ''; + org.activemq.Chat.chat(text); + return false; + } + return true; + }); + + addEvent(document.getElementById('sendB'), 'click', function() { + var text = phrase.value; + phrase.value = ''; + org.activemq.Chat.chat(text); + }); + + addEvent(document.getElementById('leaveB'), 'click', function() { + org.activemq.Chat.leave(); + return false; + }); + }; + + return { + join: function() { + var name = username.value; + if (name == null || name.length == 0) { + alert('Please enter a username!'); + } else { + user = name; + + amq.addListener('chat', chatTopic, chatHandler); + join.className = 'hidden'; + joined.className = ''; + phrase.focus(); + + amq.sendMessage(chatTopic, ''); + } + }, + + leave: function() { + amq.sendMessage(chatTopic, ''); + }, + + chat: function(text) { + if (text != null && text.length > 0) { + // TODO more encoding? + text = text.replace('<', '<'); + text = text.replace('>', '>'); + + amq.sendMessage(chatTopic, '' + text + ''); + } + }, + + init: function() { + join = document.getElementById('join'); + joined = document.getElementById('joined'); + chat = document.getElementById('chat'); + members = document.getElementById('members'); + username = document.getElementById('username'); + phrase = document.getElementById('phrase'); + + if (join.className == 'hidden' && joined.className == 'hidden') { + join.className = ''; + joined.className = 'hidden'; + username.focus(); + } + + initEventHandlers(); + } + } +}(); + + + + + + + + + + + + + Propchange: activemq/trunk/activemq-web-demo/src/main/webapp/js/chat.js ------------------------------------------------------------------------------ svn:executable = *