Selaa lähdekoodia

Fixed merge conflicts for converse.js

ichim-david 12 vuotta sitten
vanhempi
commit
083f76b7cc
3 muutettua tiedostoa jossa 301 lisäystä ja 245 poistoa
  1. 3 3
      Libraries/jarnxmpp.core.handlers.js
  2. 132 123
      converse.css
  3. 166 119
      converse.js

+ 3 - 3
Libraries/jarnxmpp.core.handlers.js

@@ -2,7 +2,7 @@
 $msg:false, Strophe:false, setTimeout:false, navigator:false, jarn:false, google:false, jarnxmpp:false, jQuery:false, sessionStorage:false, $iq:false, $pres:false, Image:false, */
 $msg:false, Strophe:false, setTimeout:false, navigator:false, jarn:false, google:false, jarnxmpp:false, jQuery:false, sessionStorage:false, $iq:false, $pres:false, Image:false, */
 
 
 (function (jarnxmpp, $, portal_url) {
 (function (jarnxmpp, $, portal_url) {
-    
+
     portal_url = portal_url || '';
     portal_url = portal_url || '';
 
 
     jarnxmpp.Storage = {
     jarnxmpp.Storage = {
@@ -230,9 +230,9 @@ $msg:false, Strophe:false, setTimeout:false, navigator:false, jarn:false, google
             data = {};
             data = {};
         }
         }
         $.ajax({
         $.ajax({
-            'url':portal_url + '/@@xmpp-loader', 
+            'url':portal_url + '/@@xmpp-loader',
             'dataType': 'json',
             'dataType': 'json',
-            'data': data, 
+            'data': data,
             'success': function (data) {
             'success': function (data) {
                 if (!(('rid' in data) && ('sid' in data) && ('BOSH_SERVICE' in data))) {
                 if (!(('rid' in data) && ('sid' in data) && ('BOSH_SERVICE' in data))) {
                     return;
                     return;

+ 132 - 123
converse.css

@@ -3,44 +3,53 @@
 }
 }
 
 
 #chatpanel {
 #chatpanel {
-	z-index: 4; /*--Keeps the panel on top of all other elements--*/
-	position: fixed;
-	bottom: 0; right: 0;
+    z-index: 4; /*--Keeps the panel on top of all other elements--*/
+    position: fixed;
+    bottom: 0; right: 0;
     height: 332px;
     height: 332px;
     width: auto;
     width: auto;
 }
 }
 
 
 #toggle-controlbox {
 #toggle-controlbox {
-	position: fixed;
+    position: fixed;
     font-size: 80%;
     font-size: 80%;
-	bottom: 0; 
+    bottom: 0;
     right: 0;
     right: 0;
     border-top-right-radius: 4px;
     border-top-right-radius: 4px;
     border-top-left-radius: 4px;
     border-top-left-radius: 4px;
-	background: #e3e2e2;
-	border: 1px solid #c3c3c3;
-	border-bottom: none;
+    background: #e3e2e2;
+    border: 1px solid #c3c3c3;
+    border-bottom: none;
     padding: 0.25em 0.5em;
     padding: 0.25em 0.5em;
     margin-right: 1em;
     margin-right: 1em;
     height: 1.1em;
     height: 1.1em;
 }
 }
 
 
+#toggle-online-users {
+    display: none;
+}
+
+#connecting-to-chat {
+    background: url('/spinner.gif') no-repeat;
+    padding-left: 1.4em;
+}
+
 .chat-head {
 .chat-head {
-	color: #ffffff;
+    color: #ffffff;
     margin: 0;
     margin: 0;
-	font-size: 100%;
+    font-size: 100%;
     border-top-right-radius: 4px;
     border-top-right-radius: 4px;
     border-top-left-radius: 4px;
     border-top-left-radius: 4px;
-	padding: 3px 0 3px 7px;
+    padding: 3px 0 3px 7px;
 }
 }
 
 
 .chat-head-chatbox {
 .chat-head-chatbox {
-	background-color: rgb(89, 106, 114);
-	background-color: rgba(89, 106, 114, 1);
+    background-color: rgb(89, 106, 114);
+    background-color: rgba(89, 106, 114, 1);
 }
 }
 
 
 .chat-head-chatroom {
 .chat-head-chatroom {
-	background-color: #2D617A;
+    background-color: #2D617A;
 }
 }
 
 
 .chatroom .chat-area {
 .chatroom .chat-area {
@@ -60,15 +69,15 @@
     height: 272px;
     height: 272px;
     background-color: white;
     background-color: white;
     overflow: auto;
     overflow: auto;
-	border-right: 1px solid #999;
-	border-bottom: 1px solid #999;
+    border-right: 1px solid #999;
+    border-bottom: 1px solid #999;
     border-bottom-right-radius: 4px;
     border-bottom-right-radius: 4px;
 }
 }
 
 
 .participants ul.participant-list li {
 .participants ul.participant-list li {
-	overflow: hidden;
-	text-overflow: ellipsis;
-	white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
     display: block;
     display: block;
     font-size: 12px;
     font-size: 12px;
     padding: 0.5em 0 0 0.5em;
     padding: 0.5em 0 0 0.5em;
@@ -89,58 +98,58 @@ input.new-chatroom-name {
 }
 }
 
 
 .chat-blink {
 .chat-blink {
-	background-color: #176689;
-	border-right:1px solid #176689;
-	border-left:1px solid #176689;
+    background-color: #176689;
+    border-right:1px solid #176689;
+    border-left:1px solid #176689;
 }
 }
 
 
 .chat-content {
 .chat-content {
     padding: 0.3em;
     padding: 0.3em;
-	font-size: 13px;
-	color: #333333;
-	height:193px;
-	overflow-y:auto;
-	border:1px solid #999;
+    font-size: 13px;
+    color: #333333;
+    height:193px;
+    overflow-y:auto;
+    border:1px solid #999;
     border-bottom: 0;
     border-bottom: 0;
     border-top: 0;
     border-top: 0;
-	background-color: #ffffff;
-	line-height: 1.3em;
+    background-color: #ffffff;
+    line-height: 1.3em;
 }
 }
 
 
 .chat-textarea {
 .chat-textarea {
-	border: 0;
+    border: 0;
     height: 50px;
     height: 50px;
     width: 100%;
     width: 100%;
 }
 }
 
 
 .chat-textarea-chatbox-selected {
 .chat-textarea-chatbox-selected {
-	border: 1px solid #578308;
-	margin:0;
+    border: 1px solid #578308;
+    margin:0;
 }
 }
 
 
 .chat-textarea-chatroom-selected {
 .chat-textarea-chatroom-selected {
-	border: 2px solid #2D617A;
-	margin:0;
+    border: 2px solid #2D617A;
+    margin:0;
 }
 }
 
 
 .chat-info {
 .chat-info {
-	color:#666666;
+    color:#666666;
 
 
 }
 }
 
 
 .chat-message-me {
 .chat-message-me {
-	font-weight: bold;
+    font-weight: bold;
     color: #436976;
     color: #436976;
 }
 }
 
 
 .chat-message-room {
 .chat-message-room {
-	font-weight: bold;
+    font-weight: bold;
     color: #4B7003;
     color: #4B7003;
     white-space: nowrap;
     white-space: nowrap;
 }
 }
 
 
 .chat-message-them {
 .chat-message-them {
-	font-weight: bold;
+    font-weight: bold;
     color: #F62817;
     color: #F62817;
     white-space: nowrap;
     white-space: nowrap;
 }
 }
@@ -149,7 +158,7 @@ input.new-chatroom-name {
     color: #808080;
     color: #808080;
 }
 }
 
 
-div#settings, 
+div#settings,
 div#chatrooms {
 div#chatrooms {
     height: 279px;
     height: 279px;
 }
 }
@@ -160,11 +169,11 @@ p.not-implemented {
     color: #808080;
     color: #808080;
 }
 }
 
 
-div.delayed .chat-message-them { 
+div.delayed .chat-message-them {
     color: #FB5D50;
     color: #FB5D50;
 }
 }
 
 
-div.delayed .chat-message-me { 
+div.delayed .chat-message-me {
     color: #7EABBB;
     color: #7EABBB;
 }
 }
 
 
@@ -175,30 +184,30 @@ div.delayed .chat-message-me {
 }
 }
 
 
 .chat-head .avatar {
 .chat-head .avatar {
-	height: 35px;
-	float: left;
-	margin-right: 6px;
+    height: 35px;
+    float: left;
+    margin-right: 6px;
 }
 }
 
 
 div.chat-title {
 div.chat-title {
     height: 1.1em;
     height: 1.1em;
     color: white;
     color: white;
-	font-weight: bold;
-	line-height: 15px;
-	display: block;
+    font-weight: bold;
+    line-height: 15px;
+    display: block;
     margin-top: 2px;
     margin-top: 2px;
-	margin-right: 20px;
-	overflow: hidden;
-	text-overflow: ellipsis;
-	white-space: nowrap;
-	text-shadow: rgba(0,0,0,0.51) 0 -1px 0;
+    margin-right: 20px;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+    text-shadow: rgba(0,0,0,0.51) 0 -1px 0;
 }
 }
 
 
 .chat-head-chatbox,
 .chat-head-chatbox,
 .chat-head-chatroom {
 .chat-head-chatroom {
     background: linear-gradient(top, rgba(206,220,231,1) 0%,rgba(89,106,114,1) 100%);
     background: linear-gradient(top, rgba(206,220,231,1) 0%,rgba(89,106,114,1) 100%);
-	height: 33px;
-	position: relative;
+    height: 33px;
+    position: relative;
 }
 }
 
 
 p.user-custom-message,
 p.user-custom-message,
@@ -207,9 +216,9 @@ p.chatroom-topic {
     font-style: italic;
     font-style: italic;
     height: 1.3em;
     height: 1.3em;
     clear: right;
     clear: right;
-	overflow: hidden;
-	text-overflow: ellipsis;
-	white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
 }
 }
 
 
 .activated{
 .activated{
@@ -224,7 +233,7 @@ a.subscribe-to-user {
 
 
 div.add-xmpp-contact {
 div.add-xmpp-contact {
     display: block;
     display: block;
-    border:1px solid #ddd; 
+    border:1px solid #ddd;
     padding: 3px 3px 3px 3px;
     padding: 3px 3px 3px 3px;
     margin: 0 0.5em;
     margin: 0 0.5em;
     clear: both;
     clear: both;
@@ -233,12 +242,12 @@ div.add-xmpp-contact {
 }
 }
 
 
 div.add-xmpp-contact a.add-xmpp-contact {
 div.add-xmpp-contact a.add-xmpp-contact {
-	text-shadow: 0 1px 0 rgba(250, 250, 250, 1);
+    text-shadow: 0 1px 0 rgba(250, 250, 250, 1);
     padding-left: 1.5em;
     padding-left: 1.5em;
 }
 }
 
 
 #fancy-xmpp-status-select a.change-xmpp-status-message {
 #fancy-xmpp-status-select a.change-xmpp-status-message {
-	text-shadow: 0 1px 0 rgba(250, 250, 250, 1);
+    text-shadow: 0 1px 0 rgba(250, 250, 250, 1);
     background: url('/pencil_icon.png') no-repeat right top;
     background: url('/pencil_icon.png') no-repeat right top;
     float: right;
     float: right;
     clear: right;
     clear: right;
@@ -247,13 +256,13 @@ div.add-xmpp-contact a.add-xmpp-contact {
 }
 }
 
 
 #fancy-xmpp-status-select a.choose-xmpp-status {
 #fancy-xmpp-status-select a.choose-xmpp-status {
-	text-shadow: 0 1px 0 rgba(250, 250, 250, 1);
+    text-shadow: 0 1px 0 rgba(250, 250, 250, 1);
     padding-left: 1.5em;
     padding-left: 1.5em;
     width: 140px;
     width: 140px;
     display: block;
     display: block;
-	overflow: hidden;
-	text-overflow: ellipsis;
-	white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
     float: left;
     float: left;
 }
 }
 
 
@@ -272,13 +281,13 @@ form.search-xmpp-contact input {
 
 
 .oc-chat-head {
 .oc-chat-head {
     margin: 0;
     margin: 0;
-	color: #FFF;
+    color: #FFF;
     border-top-right-radius: 4px;
     border-top-right-radius: 4px;
     border-top-left-radius: 4px;
     border-top-left-radius: 4px;
     height: 35px;
     height: 35px;
     clear: right;
     clear: right;
     background-color: #5390C8;
     background-color: #5390C8;
-	padding: 3px 0 0 0;
+    padding: 3px 0 0 0;
 }
 }
 
 
 .close-chatbox-button {
 .close-chatbox-button {
@@ -334,24 +343,24 @@ form.search-xmpp-contact input {
 
 
 #xmppchat-roster dd.current-xmpp-contact,
 #xmppchat-roster dd.current-xmpp-contact,
 #xmppchat-roster dd.current-xmpp-contact:hover {
 #xmppchat-roster dd.current-xmpp-contact:hover {
-	background: url(images/user_online_panel.png) no-repeat 5px 2px;
+    background: url(images/user_online_panel.png) no-repeat 5px 2px;
 }
 }
 
 
 #xmppchat-roster dd.current-xmpp-contact.offline:hover,
 #xmppchat-roster dd.current-xmpp-contact.offline:hover,
 #xmppchat-roster dd.current-xmpp-contact.unavailable:hover,
 #xmppchat-roster dd.current-xmpp-contact.unavailable:hover,
 #xmppchat-roster dd.current-xmpp-contact.offline,
 #xmppchat-roster dd.current-xmpp-contact.offline,
 #xmppchat-roster dd.current-xmpp-contact.unavailable {
 #xmppchat-roster dd.current-xmpp-contact.unavailable {
-	background: url(images/user_offline_panel.png) no-repeat 5px 2px;
+    background: url(images/user_offline_panel.png) no-repeat 5px 2px;
 }
 }
 
 
 #xmppchat-roster dd.current-xmpp-contact.busy,
 #xmppchat-roster dd.current-xmpp-contact.busy,
 #xmppchat-roster dd.current-xmpp-contact.busy:hover {
 #xmppchat-roster dd.current-xmpp-contact.busy:hover {
-	background: url(images/user_busy_panel.png) no-repeat 5px 2px;
+    background: url(images/user_busy_panel.png) no-repeat 5px 2px;
 }
 }
 
 
 #xmppchat-roster dd.current-xmpp-contact.away,
 #xmppchat-roster dd.current-xmpp-contact.away,
 #xmppchat-roster dd.current-xmpp-contact.away:hover {
 #xmppchat-roster dd.current-xmpp-contact.away:hover {
-	background: url(images/user_away_panel.png) no-repeat 5px 2px;
+    background: url(images/user_away_panel.png) no-repeat 5px 2px;
 }
 }
 
 
 #xmppchat-roster dd.requesting-xmpp-contact button{
 #xmppchat-roster dd.requesting-xmpp-contact button{
@@ -360,7 +369,7 @@ form.search-xmpp-contact input {
 
 
 #xmppchat-roster dd a {
 #xmppchat-roster dd a {
     margin-left: 2em;
     margin-left: 2em;
-	text-shadow: 0 1px 0 rgba(250, 250, 250, 1);
+    text-shadow: 0 1px 0 rgba(250, 250, 250, 1);
 }
 }
 
 
 .remove-xmpp-contact-dialog .ui-dialog-buttonpane {
 .remove-xmpp-contact-dialog .ui-dialog-buttonpane {
@@ -386,7 +395,7 @@ form.search-xmpp-contact input {
     color: #666;
     color: #666;
     border: none;
     border: none;
     padding: 0.3em 0.5em 0.3em 0.5em;
     padding: 0.3em 0.5em 0.3em 0.5em;
-	text-shadow: 0 1px 0 rgba(250, 250, 250, 1);
+    text-shadow: 0 1px 0 rgba(250, 250, 250, 1);
 }
 }
 
 
 #available-chatrooms dt {
 #available-chatrooms dt {
@@ -404,8 +413,8 @@ dd.available-chatroom,
     border: none;
     border: none;
     display: block;
     display: block;
     padding: 0 0.5em 0 0.5em;
     padding: 0 0.5em 0 0.5em;
-	color: #3f3f3f;
-	text-shadow: 0 1px 0 rgba(250, 250, 250, 1);
+    color: #3f3f3f;
+    text-shadow: 0 1px 0 rgba(250, 250, 250, 1);
 }
 }
 
 
 #xmppchat-roster dd a.remove-xmpp-contact {
 #xmppchat-roster dd a.remove-xmpp-contact {
@@ -417,8 +426,8 @@ dd.available-chatroom,
 
 
 .chatbox,
 .chatbox,
 .chatroom {
 .chatroom {
-	box-shadow: 1px 1px 5px 1px rgba(0,0,0,0.4);
-	display:none;
+    box-shadow: 1px 1px 5px 1px rgba(0,0,0,0.4);
+    display:none;
     float: right;
     float: right;
     margin-right: 15px;
     margin-right: 15px;
     z-index: 3; /* So that it's higher than the content actions */
     z-index: 3; /* So that it's higher than the content actions */
@@ -426,16 +435,16 @@ dd.available-chatroom,
 }
 }
 
 
 .chatbox {
 .chatbox {
-	width: 200px;
+    width: 200px;
 }
 }
 
 
 .chatroom {
 .chatroom {
-	width: 300px;
+    width: 300px;
     height: 311px;
     height: 311px;
 }
 }
 
 
 .oc-chat-content {
 .oc-chat-content {
-	height:272px; 
+    height:272px;
     width: 199px;
     width: 199px;
     padding: 0;
     padding: 0;
 }
 }
@@ -456,12 +465,12 @@ dd.available-chatroom,
 }
 }
 
 
 div#controlbox-panes {
 div#controlbox-panes {
-	background: -moz-linear-gradient(top, rgba(255,255,255,1) 0%, rgba(240,240,240,1) 100%); /* FF3.6+ */
-	background: -ms-linear-gradient(top, rgba(255,255,255,1) 0%,rgba(240,240,240,1) 100%); /* IE10+ */
-	background: -o-linear-gradient(top, rgba(255,255,255,1) 0%,rgba(240,240,240,1) 100%); /* Opera 11.10+ */
-	background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(255,255,255,1)), color-stop(100%,rgba(240,240,240,1))); /* Chrome,Safari4+ */
-	background: -webkit-linear-gradient(top, rgba(255,255,255,1) 0%,rgba(240,240,240,1) 100%); /* Chrome10+,Safari5.1+ */
-	background: linear-gradient(top, rgba(255,255,255,1) 0%,rgba(240,240,240,1) 100%); /* W3C */
+    background: -moz-linear-gradient(top, rgba(255,255,255,1) 0%, rgba(240,240,240,1) 100%); /* FF3.6+ */
+    background: -ms-linear-gradient(top, rgba(255,255,255,1) 0%,rgba(240,240,240,1) 100%); /* IE10+ */
+    background: -o-linear-gradient(top, rgba(255,255,255,1) 0%,rgba(240,240,240,1) 100%); /* Opera 11.10+ */
+    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(255,255,255,1)), color-stop(100%,rgba(240,240,240,1))); /* Chrome,Safari4+ */
+    background: -webkit-linear-gradient(top, rgba(255,255,255,1) 0%,rgba(240,240,240,1) 100%); /* Chrome10+,Safari5.1+ */
+    background: linear-gradient(top, rgba(255,255,255,1) 0%,rgba(240,240,240,1) 100%); /* W3C */
     background-color: white;
     background-color: white;
     border-bottom-left-radius: 4px;
     border-bottom-left-radius: 4px;
     border-bottom-right-radius: 4px;
     border-bottom-right-radius: 4px;
@@ -482,18 +491,18 @@ select#select-xmpp-status {
 /* @group Tabs */
 /* @group Tabs */
 
 
 .chat-head #controlbox-tabs {
 .chat-head #controlbox-tabs {
-	text-align: center;
-	display: inline;
-	overflow: hidden;
-	font-size: 12px;
-	list-style-type: none;
+    text-align: center;
+    display: inline;
+    overflow: hidden;
+    font-size: 12px;
+    list-style-type: none;
 }
 }
 
 
 /* single tab */
 /* single tab */
 .chat-head #controlbox-tabs li {
 .chat-head #controlbox-tabs li {
-	width: 40%;
+    width: 40%;
     float:left;
     float:left;
-	text-shadow: white 0 1px 0;
+    text-shadow: white 0 1px 0;
 }
 }
 
 
 ul#controlbox-tabs li a {
 ul#controlbox-tabs li a {
@@ -509,27 +518,27 @@ ul#controlbox-tabs li a {
     border-top-left-radius: 4px;
     border-top-left-radius: 4px;
     color:#666;
     color:#666;
     background-color:#EEE;
     background-color:#EEE;
-	background: -moz-linear-gradient(top, rgba(245,245,245,1) 0%, rgba(255,255,255,1) 100%); /* FF3.6+ */
-	background: -ms-linear-gradient(top, rgba(245,245,245,1) 0%, rgba(255,255,255,1) 100%); /* IE10+ */
-	background: -o-linear-gradient(top, rgba(245,245,245,1) 0%, rgba(255,255,255,1) 100%); /* Opera 11.10+ */
-	background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(255,255,255,1)), color-stop(100%,rgba(245,245,245,1))); /* Chrome,Safari4+ */
-	background: -webkit-linear-gradient(top, rgba(245,245,245,1) 0%, rgba(255,255,255,1) 100%); /* Chrome10+,Safari5.1+ */
-	background: linear-gradient(top, rgba(245,245,245,1) 0%, rgba(255,255,255,1) 100%); /* W3C */
-	text-shadow: 0 1px 0 rgba(250, 250, 250, 1);
+    background: -moz-linear-gradient(top, rgba(245,245,245,1) 0%, rgba(255,255,255,1) 100%); /* FF3.6+ */
+    background: -ms-linear-gradient(top, rgba(245,245,245,1) 0%, rgba(255,255,255,1) 100%); /* IE10+ */
+    background: -o-linear-gradient(top, rgba(245,245,245,1) 0%, rgba(255,255,255,1) 100%); /* Opera 11.10+ */
+    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(255,255,255,1)), color-stop(100%,rgba(245,245,245,1))); /* Chrome,Safari4+ */
+    background: -webkit-linear-gradient(top, rgba(245,245,245,1) 0%, rgba(255,255,255,1) 100%); /* Chrome10+,Safari5.1+ */
+    background: linear-gradient(top, rgba(245,245,245,1) 0%, rgba(255,255,255,1) 100%); /* W3C */
+    text-shadow: 0 1px 0 rgba(250, 250, 250, 1);
 }
 }
 
 
 .chat-head #controlbox-tabs li a:hover {
 .chat-head #controlbox-tabs li a:hover {
-	color: black;
+    color: black;
 }
 }
 
 
 .chat-head #controlbox-tabs li a {
 .chat-head #controlbox-tabs li a {
-	background-color: rgba(240,240,240,1);
-	box-shadow: inset 0 0 8px rgba(0,0,0,0.2);
+    background-color: rgba(240,240,240,1);
+    box-shadow: inset 0 0 8px rgba(0,0,0,0.2);
 }
 }
 
 
 ul#controlbox-tabs a.current, ul#controlbox-tabs a.current:hover {
 ul#controlbox-tabs a.current, ul#controlbox-tabs a.current:hover {
-	box-shadow: none; 
-    color: #000; 
+    box-shadow: none;
+    color: #000;
     border-bottom: 0;
     border-bottom: 0;
     height: 35px;
     height: 35px;
 }
 }
@@ -566,7 +575,7 @@ form.sendXMPPMessage {
     padding: 1px 2px 1px 1px;
     padding: 1px 2px 1px 1px;
 }
 }
 
 
-/* status dropdown styles */       
+/* status dropdown styles */
 dl.dropdown {
 dl.dropdown {
     margin-right: 0.5em;
     margin-right: 0.5em;
 }
 }
@@ -582,7 +591,7 @@ input.custom-xmpp-status {
 }
 }
 
 
 #fancy-xmpp-status-select {
 #fancy-xmpp-status-select {
-    border:1px solid #ddd; 
+    border:1px solid #ddd;
     height: 22px;
     height: 22px;
 }
 }
 
 
@@ -590,43 +599,43 @@ input.custom-xmpp-status {
     cursor:pointer; display:block; padding:5px;
     cursor:pointer; display:block; padding:5px;
 }
 }
 
 
-.dropdown dd ul { 
-    list-style:none; 
-    padding:5px 0; 
-    position:absolute; left:0; top:0; 
-    border:1px solid #ddd; 
+.dropdown dd ul {
+    list-style:none;
+    padding:5px 0;
+    position:absolute; left:0; top:0;
+    border:1px solid #ddd;
     border-top: 0;
     border-top: 0;
     width: 99%;
     width: 99%;
     background-color: #FFF;
     background-color: #FFF;
     z-index: 4;
     z-index: 4;
 }
 }
 
 
-.dropdown dd ul li a:hover { 
+.dropdown dd ul li a:hover {
     background-color: #bed6e5;
     background-color: #bed6e5;
 }
 }
 
 
-.dropdown span.value { 
+.dropdown span.value {
     display:none;
     display:none;
 }
 }
 
 
-.dropdown dd ul li a { 
-    padding:5px 5px 5px 30px; 
+.dropdown dd ul li a {
+    padding:5px 5px 5px 30px;
     display:block;
     display:block;
 }
 }
 
 
-.dropdown a.online { 
-	background: url(images/user_online_panel.png) no-repeat left;
+.dropdown a.online {
+    background: url(images/user_online_panel.png) no-repeat left;
 }
 }
 
 
-.dropdown a.offline { 
-	background: url(images/user_offline_panel.png) no-repeat left;
+.dropdown a.offline {
+    background: url(images/user_offline_panel.png) no-repeat left;
 }
 }
 
 
-.dropdown a.busy { 
-	background: url(images/user_busy_panel.png) no-repeat left;
+.dropdown a.busy {
+    background: url(images/user_busy_panel.png) no-repeat left;
 }
 }
 
 
-.dropdown a.away { 
-	background: url(images/user_away_panel.png) no-repeat left;
+.dropdown a.away {
+    background: url(images/user_away_panel.png) no-repeat left;
 }
 }
 
 

+ 166 - 119
converse.js

@@ -14,7 +14,7 @@
     if (console===undefined || console.log===undefined) {
     if (console===undefined || console.log===undefined) {
         console = { log: function () {}, error: function () {} };
         console = { log: function () {}, error: function () {} };
     }
     }
-    if (typeof define === 'function' && define.amd) { 
+    if (typeof define === 'function' && define.amd) {
         require.config({
         require.config({
             // paths: {
             // paths: {
             //     "patterns": "Libraries/Patterns"
             //     "patterns": "Libraries/Patterns"
@@ -25,7 +25,7 @@
                     //These script dependencies should be loaded before loading
                     //These script dependencies should be loaded before loading
                     //backbone.js
                     //backbone.js
                     deps: [
                     deps: [
-                        'Libraries/underscore', 
+                        'Libraries/underscore',
                         'jquery'],
                         'jquery'],
                     //Once loaded, use the global 'Backbone' as the
                     //Once loaded, use the global 'Backbone' as the
                     //module value.
                     //module value.
@@ -44,7 +44,6 @@
 
 
         define([
         define([
             "Libraries/burry.js/burry",
             "Libraries/burry.js/burry",
-            "Libraries/underscore.string",
             "Libraries/jquery.tinysort",
             "Libraries/jquery.tinysort",
             "Libraries/jquery-ui-1.9.1.custom",
             "Libraries/jquery-ui-1.9.1.custom",
             "Libraries/sjcl",
             "Libraries/sjcl",
@@ -63,7 +62,7 @@
                 return factory(jQuery, store, _, console);
                 return factory(jQuery, store, _, console);
             }
             }
         );
         );
-    } else { 
+    } else {
         // Browser globals
         // Browser globals
         var store = new Burry.Store('collective.xmpp.chat');
         var store = new Burry.Store('collective.xmpp.chat');
         _.templateSettings = {
         _.templateSettings = {
@@ -85,15 +84,38 @@
             pad = function (num) {
             pad = function (num) {
                 return (num < 10) ? '0' + num : '' + num;
                 return (num < 10) ? '0' + num : '' + num;
             };
             };
-            return date.getUTCFullYear() + '-' + 
-                pad(date.getUTCMonth() + 1) + '-' + 
-                pad(date.getUTCDate()) + 'T' + 
-                pad(date.getUTCHours()) + ':' + 
-                pad(date.getUTCMinutes()) + ':' + 
-                pad(date.getUTCSeconds()) + '.000Z'; 
+            return date.getUTCFullYear() + '-' +
+                pad(date.getUTCMonth() + 1) + '-' +
+                pad(date.getUTCDate()) + 'T' +
+                pad(date.getUTCHours()) + ':' +
+                pad(date.getUTCMinutes()) + ':' +
+                pad(date.getUTCSeconds()) + '.000Z';
         }
         }
     };
     };
 
 
+    xmppchat.parseISO8601 = function (datestr) {
+        /* Parses string formatted as 2013-02-14T11:27:08.268Z to a Date obj.
+        */
+        var numericKeys = [1, 4, 5, 6, 7, 10, 11],
+            struct = /^\s*(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}\.?\d*)Z\s*$/.exec(datestr),
+            minutesOffset = 0;
+
+        for (var i = 0, k; (k = numericKeys[i]); ++i) {
+            struct[k] = +struct[k] || 0;
+        }
+        // allow undefined days and months
+        struct[2] = (+struct[2] || 1) - 1;
+        struct[3] = +struct[3] || 1;
+        if (struct[8] !== 'Z' && struct[9] !== undefined) {
+            minutesOffset = struct[10] * 60 + struct[11];
+
+            if (struct[9] === '+') {
+                minutesOffset = 0 - minutesOffset;
+            }
+        }
+        return new Date(Date.UTC(struct[1], struct[2], struct[3], struct[4], struct[5] + minutesOffset, struct[6], struct[7]));
+    };
+
     xmppchat.updateMsgCounter = function () {
     xmppchat.updateMsgCounter = function () {
         this.msg_counter += 1;
         this.msg_counter += 1;
         if (this.msg_counter > 0) {
         if (this.msg_counter > 0) {
@@ -110,7 +132,7 @@
     };
     };
 
 
     xmppchat.collections = {
     xmppchat.collections = {
-        /* FIXME: XEP-0136 specifies 'urn:xmpp:archive' but the mod_archive_odbc 
+        /* FIXME: XEP-0136 specifies 'urn:xmpp:archive' but the mod_archive_odbc
         *  add-on for ejabberd wants the URL below. This might break for other
         *  add-on for ejabberd wants the URL below. This might break for other
         *  Jabber servers.
         *  Jabber servers.
         */
         */
@@ -128,17 +150,17 @@
                     .c('max')
                     .c('max')
                     .t('1');
                     .t('1');
 
 
-        xmppchat.connection.sendIQ(iq, 
+        xmppchat.connection.sendIQ(iq,
                     callback,
                     callback,
-                    function () { 
-                        console.log('Error while retrieving collections'); 
+                    function () {
+                        console.log('Error while retrieving collections');
                     });
                     });
     };
     };
 
 
     xmppchat.collections.getLastMessages = function (jid, callback) {
     xmppchat.collections.getLastMessages = function (jid, callback) {
         var that = this;
         var that = this;
         this.getLastCollection(jid, function (result) {
         this.getLastCollection(jid, function (result) {
-            // Retrieve the last page of a collection (max 30 elements). 
+            // Retrieve the last page of a collection (max 30 elements).
             var $collection = $(result).find('chat'),
             var $collection = $(result).find('chat'),
                 jid = $collection.attr('with'),
                 jid = $collection.attr('with'),
                 start = $collection.attr('start'),
                 start = $collection.attr('start'),
@@ -197,7 +219,7 @@
 
 
         getOpenChats: function () {
         getOpenChats: function () {
             var key = hex_sha1(this.get('own_jid')+'-open-chats'),
             var key = hex_sha1(this.get('own_jid')+'-open-chats'),
-                chats = store.get(key) || [], 
+                chats = store.get(key) || [],
                 decrypted_chats = [],
                 decrypted_chats = [],
                 i;
                 i;
 
 
@@ -234,7 +256,7 @@
             store.flush();
             store.flush();
         }
         }
     });
     });
-    
+
     xmppchat.ChatBox = Backbone.Model.extend({
     xmppchat.ChatBox = Backbone.Model.extend({
         initialize: function () {
         initialize: function () {
             this.set({
             this.set({
@@ -258,15 +280,15 @@
         },
         },
 
 
         message_template: _.template(
         message_template: _.template(
-                            '<div class="chat-message {{extra_classes}}">' + 
-                                '<span class="chat-message-{{sender}}">{{time}} {{username}}:&nbsp;</span>' + 
-                                '<span class="chat-message-content">{{message}}</span>' + 
+                            '<div class="chat-message {{extra_classes}}">' +
+                                '<span class="chat-message-{{sender}}">{{time}} {{username}}:&nbsp;</span>' +
+                                '<span class="chat-message-content">{{message}}</span>' +
                             '</div>'),
                             '</div>'),
 
 
         action_template: _.template(
         action_template: _.template(
-                            '<div class="chat-message {{extra_classes}}">' + 
-                                '<span class="chat-message-{{sender}}">{{time}}:&nbsp;</span>' + 
-                                '<span class="chat-message-content">{{message}}</span>' + 
+                            '<div class="chat-message {{extra_classes}}">' +
+                                '<span class="chat-message-{{sender}}">{{time}}:&nbsp;</span>' +
+                                '<span class="chat-message-content">{{message}}</span>' +
                             '</div>'),
                             '</div>'),
 
 
         autoLink: function (text) {
         autoLink: function (text) {
@@ -279,7 +301,7 @@
             var now = new Date(),
             var now = new Date(),
                 time = now.toLocaleTimeString().substring(0,5),
                 time = now.toLocaleTimeString().substring(0,5),
                 minutes = now.getMinutes().toString(),
                 minutes = now.getMinutes().toString(),
-                $chat_content = $(this.el).find('.chat-content');
+                $chat_content = this.$el.find('.chat-content');
 
 
             var msg = xmppchat.storage.getLastMessage(this.model.get('jid'));
             var msg = xmppchat.storage.getLastMessage(this.model.get('jid'));
             if (typeof msg !== 'undefined') {
             if (typeof msg !== 'undefined') {
@@ -293,9 +315,9 @@
             if (minutes.length==1) {minutes = '0'+minutes;}
             if (minutes.length==1) {minutes = '0'+minutes;}
             $chat_content.find('div.chat-event').remove();
             $chat_content.find('div.chat-event').remove();
             $chat_content.append(this.message_template({
             $chat_content.append(this.message_template({
-                                'sender': 'me', 
-                                'time': time, 
-                                'message': message, 
+                                'sender': 'me',
+                                'time': time,
+                                'message': message,
                                 'username': 'me',
                                 'username': 'me',
                                 'extra_classes': ''
                                 'extra_classes': ''
                             }));
                             }));
@@ -310,14 +332,14 @@
         },
         },
 
 
         messageReceived: function (message) {
         messageReceived: function (message) {
-            /* XXX: event.mtype should be 'xhtml' for XHTML-IM messages, 
-                but I only seem to get 'text'. 
+            /* XXX: event.mtype should be 'xhtml' for XHTML-IM messages,
+                but I only seem to get 'text'.
             */
             */
             var body = this.autoLink($message.children('body').text()),
             var body = this.autoLink($message.children('body').text()),
                 from = Strophe.getBareJidFromJid($message.attr('from')),
                 from = Strophe.getBareJidFromJid($message.attr('from')),
                 to = $message.attr('to'),
                 to = $message.attr('to'),
                 composing = $message.find('composing'),
                 composing = $message.find('composing'),
-                $chat_content = $(this.el).find('.chat-content'),
+                $chat_content = this.$el.find('.chat-content'),
                 delayed = $message.find('delay').length > 0,
                 delayed = $message.find('delay').length > 0,
                 fullname = this.model.get('fullname'),
                 fullname = this.model.get('fullname'),
                 time, stamp, username, sender;
                 time, stamp, username, sender;
@@ -347,13 +369,13 @@
                     // XXX: Test properly (for really old messages we somehow need to show
                     // XXX: Test properly (for really old messages we somehow need to show
                     // their date as well)
                     // their date as well)
                     stamp = $message.find('delay').attr('stamp');
                     stamp = $message.find('delay').attr('stamp');
-                    time = (new Date(stamp)).toLocaleTimeString().substring(0,5); 
+                    time = (new Date(stamp)).toLocaleTimeString().substring(0,5);
                 } else {
                 } else {
-                    time = (new Date()).toLocaleTimeString().substring(0,5); 
+                    time = (new Date()).toLocaleTimeString().substring(0,5);
                 }
                 }
                 $chat_content.append(
                 $chat_content.append(
                         this.message_template({
                         this.message_template({
-                            'sender': sender, 
+                            'sender': sender,
                             'time': time,
                             'time': time,
                             'message': body,
                             'message': body,
                             'username': username,
                             'username': username,
@@ -370,11 +392,11 @@
 
 
         insertClientStoredMessages: function () {
         insertClientStoredMessages: function () {
             var msgs = xmppchat.storage.getMessages(this.model.get('jid')),
             var msgs = xmppchat.storage.getMessages(this.model.get('jid')),
-                $content = this.$el.find('.chat-content'), 
-                prev_date, this_date, now, separator, i; 
+                $content = this.$el.find('.chat-content'),
+                prev_date, this_date, now, separator, i;
 
 
             for (i=0; i<_.size(msgs); i++) {
             for (i=0; i<_.size(msgs); i++) {
-                var msg = msgs[i], 
+                var msg = msgs[i],
                     msg_array = msg.split(' ', 2),
                     msg_array = msg.split(' ', 2),
                     date = msg_array[0];
                     date = msg_array[0];
 
 
@@ -395,16 +417,16 @@
                 if (msg_array[1] == 'to') {
                 if (msg_array[1] == 'to') {
                     $content.append(
                     $content.append(
                         this.message_template({
                         this.message_template({
-                            'sender': 'me', 
+                            'sender': 'me',
                             'time': this_date.toLocaleTimeString().substring(0,5),
                             'time': this_date.toLocaleTimeString().substring(0,5),
-                            'message': msg, 
+                            'message': msg,
                             'username': 'me',
                             'username': 'me',
                             'extra_classes': 'delayed'
                             'extra_classes': 'delayed'
                     }));
                     }));
                 } else {
                 } else {
                     $content.append(
                     $content.append(
                         this.message_template({
                         this.message_template({
-                            'sender': 'them', 
+                            'sender': 'them',
                             'time': this_date.toLocaleTimeString().substring(0,5),
                             'time': this_date.toLocaleTimeString().substring(0,5),
                             'message': msg,
                             'message': msg,
                             'username': this.model.get('fullname').split(' ')[0],
                             'username': this.model.get('fullname').split(' ')[0],
@@ -414,25 +436,35 @@
             }
             }
         },
         },
 
 
+        addHelpMessages: function (msgs) {
+            var $chat_content = this.$el.find('.chat-content'), i;
+            for (i=0; i<msgs.length; i++) {
+                $chat_content.append($('<div class="chat-help">'+msgs[i]+'</div>'));
+            }
+            this.scrolldown();
+        },
+
         sendMessage: function (text) {
         sendMessage: function (text) {
             // TODO: Look in ChatPartners to see what resources we have for the recipient.
             // TODO: Look in ChatPartners to see what resources we have for the recipient.
             // if we have one resource, we sent to only that resources, if we have multiple
             // if we have one resource, we sent to only that resources, if we have multiple
             // we send to the bare jid.
             // we send to the bare jid.
             var timestamp = (new Date()).getTime(),
             var timestamp = (new Date()).getTime(),
                 bare_jid = this.model.get('jid'),
                 bare_jid = this.model.get('jid'),
-                match = text.replace(/^\s*/, "").match(/^\/(.*)\s*$/), el, $chat_content;
+                match = text.replace(/^\s*/, "").match(/^\/(.*)\s*$/), el, $chat_content,
+                msgs;
 
 
             if (match) {
             if (match) {
                 if (match[1] === "clear") {
                 if (match[1] === "clear") {
-                    $(this.el).find('.chat-content').empty();
+                    this.$el.find('.chat-content').empty();
                     xmppchat.storage.clearMessages(bare_jid);
                     xmppchat.storage.clearMessages(bare_jid);
                     return;
                     return;
                 }
                 }
                 else if (match[1] === "help") {
                 else if (match[1] === "help") {
-                    $chat_content = $(this.el).find('.chat-content');
-                    $chat_content.append($('<div class="chat-help"><strong>/help</strong>: Show this menu</div>'));
-                    $chat_content.append($('<div class="chat-help"><strong>/clear</strong>: Remove messages</div>'));
-                    this.scrolldown();
+                    msgs =  [
+                        '<strong>/help</strong>: Show this menu', 
+                        '<strong>/clear</strong>: Remove messages' 
+                        ];
+                    this.addHelpMessages(msgs);
                     return;
                     return;
                 }
                 }
             }
             }
@@ -467,14 +499,19 @@
                 if (message !== '') {
                 if (message !== '') {
                     this.sendMessage(message);
                     this.sendMessage(message);
                 }
                 }
-                $(this.el).data('composing', false);
+                this.$el.data('composing', false);
             } else {
             } else {
-                composing = $(this.el).data('composing');
-                if (!composing) {
-                    notify = $msg({'to':this.model.get('jid'), 'type': 'chat'})
-                                    .c('composing', {'xmlns':'http://jabber.org/protocol/chatstates'});
-                    xmppchat.connection.send(notify);
-                    $(this.el).data('composing', true);
+                composing = this.$el.data('composing');
+                if (!composing) { 
+                    if (ev.keyCode != 47) {
+                        // We don't send composing messages if the message
+                        // starts with forward-slash.
+                        notify = $msg({'to':this.model.get('jid'), 'type': 'chat'})
+                                        .c('composing', {'xmlns':'http://jabber.org/protocol/chatstates'});
+                        xmppchat.connection.send(notify);
+                        this.$el.data('composing', true);
+                    }
+                    this.$el.data('composing', true);
                 }
                 }
             }
             }
         },
         },
@@ -527,7 +564,7 @@
                         '</a>' +
                         '</a>' +
                         '<p class="user-custom-message"><p/>' +
                         '<p class="user-custom-message"><p/>' +
                     '</div>' +
                     '</div>' +
-                    '<div class="chat-content"></div>' + 
+                    '<div class="chat-content"></div>' +
                     '<form class="sendXMPPMessage" action="" method="post">' +
                     '<form class="sendXMPPMessage" action="" method="post">' +
                     '<textarea ' +
                     '<textarea ' +
                         'type="text" ' +
                         'type="text" ' +
@@ -536,18 +573,18 @@
                     '</form>'),
                     '</form>'),
 
 
         render: function () {
         render: function () {
-            $(this.el).attr('id', this.model.get('box_id'));
-            $(this.el).html(this.template(this.model.toJSON()));
+            this.$el.attr('id', this.model.get('box_id'));
+            this.$el.html(this.template(this.model.toJSON()));
             this.insertClientStoredMessages();
             this.insertClientStoredMessages();
             return this;
             return this;
         },
         },
 
 
         isVisible: function () {
         isVisible: function () {
-            return $(this.el).is(':visible');
+            return this.$el.is(':visible');
         },
         },
 
 
         focus: function () {
         focus: function () {
-            $(this.el).find('.chat-textarea').focus();
+            this.$el.find('.chat-textarea').focus();
             return this;
             return this;
         },
         },
 
 
@@ -614,7 +651,7 @@
             $.getJSON(portal_url + "/search-users?q=" + $(ev.target).find('input.username').val(), function (data) {
             $.getJSON(portal_url + "/search-users?q=" + $(ev.target).find('input.username').val(), function (data) {
                 var $results_el = $('#found-users');
                 var $results_el = $('#found-users');
                 $(data).each(function (idx, obj) {
                 $(data).each(function (idx, obj) {
-                    if ($results_el.children().length > 0) {  
+                    if ($results_el.children().length > 0) {
                         $results_el.empty();
                         $results_el.empty();
                     }
                     }
                     $results_el.append(
                     $results_el.append(
@@ -683,7 +720,7 @@
 
 
         updateRoomsList: function () {
         updateRoomsList: function () {
             xmppchat.connection.muc.listRooms(xmppchat.connection.muc_domain, $.proxy(function (iq) {
             xmppchat.connection.muc.listRooms(xmppchat.connection.muc_domain, $.proxy(function (iq) {
-                var room, name, jid, i, 
+                var room, name, jid, i,
                     rooms = $(iq).find('query').find('item');
                     rooms = $(iq).find('query').find('item');
                 this.$el.find('#available-chatrooms').find('dd.available-chatroom').remove();
                 this.$el.find('#available-chatrooms').find('dd.available-chatroom').remove();
                 if (rooms.length) {
                 if (rooms.length) {
@@ -706,7 +743,7 @@
             if (ev.type === 'click') {
             if (ev.type === 'click') {
                 jid = $(ev.target).attr('data-room-jid');
                 jid = $(ev.target).attr('data-room-jid');
             } else {
             } else {
-                name = _.str.strip($(ev.target).find('input.new-chatroom-name').val()).toLowerCase();
+                name = $(ev.target).find('input.new-chatroom-name').val().trim().toLowerCase();
                 if (name) {
                 if (name) {
                     jid = Strophe.escapeNode(name) + '@' + xmppchat.connection.muc_domain;
                     jid = Strophe.escapeNode(name) + '@' + xmppchat.connection.muc_domain;
                 } else {
                 } else {
@@ -761,7 +798,7 @@
                 $tab_panel = $($tab.attr('href')),
                 $tab_panel = $($tab.attr('href')),
                 $sibling_panel = $($sibling.attr('href'));
                 $sibling_panel = $($sibling.attr('href'));
 
 
-            $sibling_panel.fadeOut('fast', function () { 
+            $sibling_panel.fadeOut('fast', function () {
                 $sibling.removeClass('current');
                 $sibling.removeClass('current');
                 $tab.addClass('current');
                 $tab.addClass('current');
                 $tab_panel.fadeIn('fast', function () {
                 $tab_panel.fadeIn('fast', function () {
@@ -769,6 +806,11 @@
             });
             });
         },
         },
 
 
+        addHelpMessages: function (msgs) {
+            // Override addHelpMessages in ChatBoxView, for now do nothing.
+            return;
+        },
+
         render: function () {
         render: function () {
             var that = this;
             var that = this;
             this.$el.hide('fast', function () {
             this.$el.hide('fast', function () {
@@ -803,8 +845,8 @@
         closeChatRoom: function () {
         closeChatRoom: function () {
             this.closeChat();
             this.closeChat();
             xmppchat.connection.muc.leave(
             xmppchat.connection.muc.leave(
-                            this.model.get('jid'), 
-                            this.model.get('nick'), 
+                            this.model.get('jid'),
+                            this.model.get('nick'),
                             this.onLeave,
                             this.onLeave,
                             undefined);
                             undefined);
             delete xmppchat.chatboxesview.views[this.model.get('jid')];
             delete xmppchat.chatboxesview.views[this.model.get('jid')];
@@ -824,12 +866,13 @@
                 message = message.replace(/^\s+|\s+jQuery/g,"");
                 message = message.replace(/^\s+|\s+jQuery/g,"");
                 $textarea.val('').focus();
                 $textarea.val('').focus();
                 if (message !== '') {
                 if (message !== '') {
-                    this.sendGroupMessage(message);
+                    this.sendChatRoomMessage(message);
                 }
                 }
-            } 
+            }
         },
         },
 
 
-        sendGroupMessage: function (body) {
+        sendChatRoomMessage: function (body) {
+            this.appendMessage(body);
             var match = body.replace(/^\s*/, "").match(/^\/(.*?)(?: (.*))?$/) || [false];
             var match = body.replace(/^\s*/, "").match(/^\/(.*?)(?: (.*))?$/) || [false];
             switch (match[1]) {
             switch (match[1]) {
                 case 'msg':
                 case 'msg':
@@ -851,7 +894,7 @@
                     xmppchat.connection.muc.deop(this.model.get('jid'), match[2]);
                     xmppchat.connection.muc.deop(this.model.get('jid'), match[2]);
                     break;
                     break;
                 case 'help':
                 case 'help':
-                    $chat_content = $(this.el).find('.chat-content');
+                    $chat_content = this.$el.find('.chat-content');
                     $chat_content.append($('<div class="chat-help"><strong>/help</strong>: Show this menu</div>'));
                     $chat_content.append($('<div class="chat-help"><strong>/help</strong>: Show this menu</div>'));
                     $chat_content.append($('<div class="chat-help"><strong>/topic</strong>: Set chatroom topic</div>'));
                     $chat_content.append($('<div class="chat-help"><strong>/topic</strong>: Set chatroom topic</div>'));
                     /* TODO:
                     /* TODO:
@@ -893,9 +936,9 @@
             xmppchat.connection.muc.join(
             xmppchat.connection.muc.join(
                             this.model.get('jid'), 
                             this.model.get('jid'), 
                             this.model.get('nick'), 
                             this.model.get('nick'), 
-                            $.proxy(this.onMessage, this), 
-                            $.proxy(this.onPresence, this), 
-                            $.proxy(this.onRoster, this));
+                            $.proxy(this.onChatRoomMessage, this), 
+                            $.proxy(this.onChatRoomPresence, this), 
+                            $.proxy(this.onChatRoomRoster, this));
         },
         },
 
 
         onLeave: function () {
         onLeave: function () {
@@ -905,7 +948,7 @@
             }
             }
         },
         },
 
 
-        onPresence: function (presence, room) {
+        onChatRoomPresence: function (presence, room) {
             var nick = room.nick,
             var nick = room.nick,
                 from = $(presence).attr('from');
                 from = $(presence).attr('from');
             if ($(presence).attr('type') !== 'error') {
             if ($(presence).attr('type') !== 'error') {
@@ -920,11 +963,11 @@
             return true;
             return true;
         },
         },
 
 
-        onMessage: function (message) {
+        onChatRoomMessage: function (message) {
             var body = $(message).children('body').text(),
             var body = $(message).children('body').text(),
                 jid = $(message).attr('from'),
                 jid = $(message).attr('from'),
                 composing = $(message).find('composing'),
                 composing = $(message).find('composing'),
-                $chat_content = $(this.el).find('.chat-content'),
+                $chat_content = this.$el.find('.chat-content'),
                 sender = Strophe.unescapeNode(Strophe.getResourceFromJid(jid)),
                 sender = Strophe.unescapeNode(Strophe.getResourceFromJid(jid)),
                 subject = $(message).children('subject').text();
                 subject = $(message).children('subject').text();
 
 
@@ -938,7 +981,8 @@
                 }
                 }
             } else {
             } else {
                 if (sender === this.model.get('nick')) {
                 if (sender === this.model.get('nick')) {
-                    this.appendMessage(body);
+                    // Our own message which is already appended 
+                    return true;
                 } else {
                 } else {
                     $chat_content.find('div.chat-event').remove();
                     $chat_content.find('div.chat-event').remove();
 
 
@@ -947,16 +991,16 @@
                         body = body.replace(/^\/me/, '*'+sender);
                         body = body.replace(/^\/me/, '*'+sender);
                         $chat_content.append(
                         $chat_content.append(
                                 this.action_template({
                                 this.action_template({
-                                    'sender': 'room', 
+                                    'sender': 'room',
                                     'time': (new Date()).toLocaleTimeString().substring(0,5),
                                     'time': (new Date()).toLocaleTimeString().substring(0,5),
-                                    'message': body, 
+                                    'message': body,
                                     'username': sender,
                                     'username': sender,
                                     'extra_classes': ($(message).find('delay').length > 0) && 'delayed' || ''
                                     'extra_classes': ($(message).find('delay').length > 0) && 'delayed' || ''
                                 }));
                                 }));
                     } else {
                     } else {
                         $chat_content.append(
                         $chat_content.append(
                                 this.message_template({
                                 this.message_template({
-                                    'sender': 'room', 
+                                    'sender': 'room',
                                     'time': (new Date()).toLocaleTimeString().substring(0,5),
                                     'time': (new Date()).toLocaleTimeString().substring(0,5),
                                     'message': body,
                                     'message': body,
                                     'username': sender,
                                     'username': sender,
@@ -969,7 +1013,7 @@
             return true;
             return true;
         },
         },
 
 
-        onRoster: function (roster, room) {
+        onChatRoomRoster: function (roster, room) {
             var controlboxview = xmppchat.chatboxesview.views.controlbox,
             var controlboxview = xmppchat.chatboxesview.views.controlbox,
                 i;
                 i;
 
 
@@ -991,8 +1035,8 @@
         },
         },
 
 
         render: function () {
         render: function () {
-            $(this.el).attr('id', this.model.get('box_id'));
-            $(this.el).html(this.template(this.model.toJSON()));
+            this.$el.attr('id', this.model.get('box_id'));
+            this.$el.html(this.template(this.model.toJSON()));
             return this;
             return this;
         }
         }
     });
     });
@@ -1012,7 +1056,7 @@
             }
             }
             _.each(open_chats, $.proxy(function (jid) {
             _.each(open_chats, $.proxy(function (jid) {
                 if (jid != 'controlbox') {
                 if (jid != 'controlbox') {
-                    if (_.str.include(jid, xmppchat.connection.muc_domain)) {
+                    if (strinclude(jid, xmppchat.connection.muc_domain)) {
                         this.createChatBox(jid);
                         this.createChatBox(jid);
                     } else {
                     } else {
                         this.openChat(jid);
                         this.openChat(jid);
@@ -1020,11 +1064,11 @@
                 }
                 }
             }, this));
             }, this));
         },
         },
-        
+
         isChatRoom: function (jid) {
         isChatRoom: function (jid) {
             return Strophe.getDomainFromJid(jid) === xmppchat.connection.muc_domain;
             return Strophe.getDomainFromJid(jid) === xmppchat.connection.muc_domain;
         },
         },
-        
+
         createChatBox: function (jid, data) {
         createChatBox: function (jid, data) {
             var box, view;
             var box, view;
             if (this.isChatRoom(jid)) {
             if (this.isChatRoom(jid)) {
@@ -1034,14 +1078,14 @@
                 });
                 });
             } else {
             } else {
                 box = new xmppchat.ChatBox({
                 box = new xmppchat.ChatBox({
-                                        'id': jid, 
-                                        'jid': jid, 
-                                        'fullname': data.fullname, 
+                                        'id': jid,
+                                        'jid': jid,
+                                        'fullname': data.fullname,
                                         'portrait_url': data.portrait_url,
                                         'portrait_url': data.portrait_url,
                                         'user_profile_url': data.user_profile_url
                                         'user_profile_url': data.user_profile_url
                                     });
                                     });
                 view = new xmppchat.ChatBoxView({
                 view = new xmppchat.ChatBoxView({
-                    model: box 
+                    model: box
                 });
                 });
             }
             }
             this.views[jid] = view.render();
             this.views[jid] = view.render();
@@ -1068,7 +1112,7 @@
                 $.getJSON(portal_url + "/xmpp-userinfo?user_id=" + Strophe.getNodeFromJid(jid), $.proxy(function (data) {
                 $.getJSON(portal_url + "/xmpp-userinfo?user_id=" + Strophe.getNodeFromJid(jid), $.proxy(function (data) {
                     view = this.createChatBox(jid, data);
                     view = this.createChatBox(jid, data);
                 }, this));
                 }, this));
-            } 
+            }
         },
         },
 
 
         showChat: function (jid) {
         showChat: function (jid) {
@@ -1081,8 +1125,8 @@
                     view.scrolldown();
                     view.scrolldown();
                     view.focus();
                     view.focus();
                 }
                 }
-                view.saveChatToStorage();
             }
             }
+            view.saveChatToStorage();
             return view;
             return view;
         },
         },
 
 
@@ -1172,7 +1216,7 @@
                 'bare_jid': Strophe.getBareJidFromJid(jid),
                 'bare_jid': Strophe.getBareJidFromJid(jid),
                 'user_id': user_id,
                 'user_id': user_id,
                 'subscription': subscription,
                 'subscription': subscription,
-                'fullname': name, 
+                'fullname': name,
                 'resources': [],
                 'resources': [],
                 'presence_type': 'offline',
                 'presence_type': 'offline',
                 'status': 'offline'
                 'status': 'offline'
@@ -1251,15 +1295,14 @@
                 ask = item.get('ask'),
                 ask = item.get('ask'),
                 that = this,
                 that = this,
                 subscription = item.get('subscription');
                 subscription = item.get('subscription');
-
-            $(this.el).addClass(item.get('presence_type'));
+            this.$el.addClass(item.get('presence_type'));
             
             
             if (ask === 'subscribe') {
             if (ask === 'subscribe') {
                 this.$el.addClass('pending-xmpp-contact');
                 this.$el.addClass('pending-xmpp-contact');
-                $(this.el).html(this.pending_template(item.toJSON()));
+                this.$el.html(this.pending_template(item.toJSON()));
             } else if (ask === 'request') {
             } else if (ask === 'request') {
                 this.$el.addClass('requesting-xmpp-contact');
                 this.$el.addClass('requesting-xmpp-contact');
-                $(this.el).html(this.request_template(item.toJSON()));
+                this.$el.html(this.request_template(item.toJSON()));
                 this.$el.delegate('button.accept-xmpp-request', 'click', function (ev) {
                 this.$el.delegate('button.accept-xmpp-request', 'click', function (ev) {
                     ev.preventDefault();
                     ev.preventDefault();
                     that.acceptRequest();
                     that.acceptRequest();
@@ -1277,7 +1320,7 @@
                     that.openChat();
                     that.openChat();
                 });
                 });
             }
             }
-            
+
             // Event handlers
             // Event handlers
             this.$el.delegate('a.remove-xmpp-contact','click', function (ev) {
             this.$el.delegate('a.remove-xmpp-contact','click', function (ev) {
                 ev.preventDefault();
                 ev.preventDefault();
@@ -1289,7 +1332,7 @@
         initialize: function () {
         initialize: function () {
             this.options.model.on('change', function (item, changed) {
             this.options.model.on('change', function (item, changed) {
                 if (_.has(changed.changes, 'presence_type')) {
                 if (_.has(changed.changes, 'presence_type')) {
-                    $(this.el).attr('class', item.changed.presence_type);
+                    this.$el.attr('class', item.changed.presence_type);
                 }
                 }
             }, this);
             }, this);
         }
         }
@@ -1305,7 +1348,7 @@
             var presence_type = rosteritem.get('presence_type'),
             var presence_type = rosteritem.get('presence_type'),
                 rank = 4;
                 rank = 4;
             switch(presence_type) {
             switch(presence_type) {
-                case 'offline': 
+                case 'offline':
                     rank = 0;
                     rank = 0;
                     break;
                     break;
                 case 'unavailable':
                 case 'unavailable':
@@ -1354,7 +1397,7 @@
             model.options = options || {};
             model.options = options || {};
             this.add(model);
             this.add(model);
         },
         },
-            
+
         addResource: function (bare_jid, resource) {
         addResource: function (bare_jid, resource) {
             var item = this.getItem(bare_jid),
             var item = this.getItem(bare_jid),
                 resources;
                 resources;
@@ -1446,13 +1489,13 @@
             if (this.isSelf(bare_jid)) {
             if (this.isSelf(bare_jid)) {
                 if (xmppchat.connection.jid != jid) {
                 if (xmppchat.connection.jid != jid) {
                     // Another resource has changed it's status, we'll update ours as well.
                     // Another resource has changed it's status, we'll update ours as well.
-                    // FIXME: We should ideally differentiate between converse.js using 
+                    // FIXME: We should ideally differentiate between converse.js using
                     // resources and other resources (i.e Pidgin etc.)
                     // resources and other resources (i.e Pidgin etc.)
                     xmppchat.xmppstatus.set({'status': presence_type});
                     xmppchat.xmppstatus.set({'status': presence_type});
-                } 
+                }
                 return true;
                 return true;
             } else if (($(presence).find('x').attr('xmlns') || '').indexOf(Strophe.NS.MUC) === 0) {
             } else if (($(presence).find('x').attr('xmlns') || '').indexOf(Strophe.NS.MUC) === 0) {
-                return true; // Ignore MUC 
+                return true; // Ignore MUC
             }
             }
 
 
             if ((status_message.length > 0) && (status_message.text() && (presence_type !== 'unavailable'))) {
             if ((status_message.length > 0) && (status_message.text() && (presence_type !== 'unavailable'))) {
@@ -1497,10 +1540,10 @@
                 }
                 }
 
 
             } else if (presence_type === 'unsubscribed') {
             } else if (presence_type === 'unsubscribed') {
-                /* Upon receiving the presence stanza of type "unsubscribed", 
-                * the user SHOULD acknowledge receipt of that subscription state 
-                * notification by sending a presence stanza of type "unsubscribe" 
-                * this step lets the user's server know that it MUST no longer 
+                /* Upon receiving the presence stanza of type "unsubscribed",
+                * the user SHOULD acknowledge receipt of that subscription state
+                * notification by sending a presence stanza of type "unsubscribe"
+                * this step lets the user's server know that it MUST no longer
                 * send notification of the subscription state change to the user.
                 * send notification of the subscription state change to the user.
                 */
                 */
                 xmppchat.xmppstatus.sendPresence('unsubscribe');
                 xmppchat.xmppstatus.sendPresence('unsubscribe');
@@ -1508,7 +1551,7 @@
                     xmppchat.chatboxesview.controlbox.roster.remove(bare_jid);
                     xmppchat.chatboxesview.controlbox.roster.remove(bare_jid);
                     xmppchat.connection.roster.remove(bare_jid);
                     xmppchat.connection.roster.remove(bare_jid);
                 }
                 }
-            } else { 
+            } else {
                 if ((presence_type === undefined) && (show)) {
                 if ((presence_type === undefined) && (show)) {
                     if (show.text() === 'chat') {
                     if (show.text() === 'chat') {
                         presence_type = 'online';
                         presence_type = 'online';
@@ -1742,7 +1785,7 @@
         updateStatusUI: function (ev) {
         updateStatusUI: function (ev) {
             var stat = ev.get('status'),
             var stat = ev.get('status'),
                 status_message = ev.get('status_message') || "I am " + stat;
                 status_message = ev.get('status_message') || "I am " + stat;
-            $(this.el).find('#fancy-xmpp-status-select').html(
+            this.$el.find('#fancy-xmpp-status-select').html(
                 this.status_template({
                 this.status_template({
                         'presence_type': stat,
                         'presence_type': stat,
                         'status_message': status_message
                         'status_message': status_message
@@ -1767,20 +1810,20 @@
         initialize: function () {
         initialize: function () {
             // Replace the default dropdown with something nicer
             // Replace the default dropdown with something nicer
             // -------------------------------------------------
             // -------------------------------------------------
-            var $select = $(this.el).find('select#select-xmpp-status'),
+            var $select = this.$el.find('select#select-xmpp-status'),
                 presence_type = this.model.getStatus() || 'offline',
                 presence_type = this.model.getStatus() || 'offline',
                 options = $('option', $select),
                 options = $('option', $select),
                 that = this;
                 that = this;
-            $(this.el).html(this.choose_template());
-            $(this.el).find('#fancy-xmpp-status-select')
+            this.$el.html(this.choose_template());
+            this.$el.find('#fancy-xmpp-status-select')
                     .html(this.status_template({
                     .html(this.status_template({
                             'status_message': "I am " + presence_type,
                             'status_message': "I am " + presence_type,
-                            'presence_type': presence_type 
+                            'presence_type': presence_type
                             }));
                             }));
             // iterate through all the <option> elements and create UL
             // iterate through all the <option> elements and create UL
             options.each(function(){
             options.each(function(){
                 $(that.el).find("#target dd ul").append(that.option_template({
                 $(that.el).find("#target dd ul").append(that.option_template({
-                                                                'value': $(this).val(), 
+                                                                'value': $(this).val(),
                                                                 'text': $(this).text()
                                                                 'text': $(this).text()
                                                             })).hide();
                                                             })).hide();
             });
             });
@@ -1788,7 +1831,7 @@
 
 
             // Listen for status change on the model and initialize
             // Listen for status change on the model and initialize
             // ----------------------------------------------------
             // ----------------------------------------------------
-            this.options.model.on("change", $.proxy(this.updateStatusUI, this)); 
+            this.options.model.on("change", $.proxy(this.updateStatusUI, this));
             this.model.initStatus();
             this.model.initStatus();
         }
         }
     });
     });
@@ -1796,7 +1839,8 @@
     // Event handlers
     // Event handlers
     // --------------
     // --------------
     $(document).ready($.proxy(function () {
     $(document).ready($.proxy(function () {
-        var chatdata = jQuery('div#collective-xmpp-chat-data'),
+        var chatdata = $('div#collective-xmpp-chat-data'),
+            $connecting = $('span#connecting-to-chat'),
             $toggle = $('a#toggle-online-users');
             $toggle = $('a#toggle-online-users');
         $toggle.unbind('click');
         $toggle.unbind('click');
 
 
@@ -1809,6 +1853,8 @@
         }).render();
         }).render();
 
 
         $(document).bind('jarnxmpp.disconnected', $.proxy(function (ev, conn) {
         $(document).bind('jarnxmpp.disconnected', $.proxy(function (ev, conn) {
+            $connecting.show();
+            $toggle.hide();
             console.log("Connection Failed :(");
             console.log("Connection Failed :(");
         }, this));
         }, this));
 
 
@@ -1825,13 +1871,12 @@
             this.chatboxes = new this.ChatBoxes();
             this.chatboxes = new this.ChatBoxes();
             this.chatboxesview = new this.ChatBoxesView({'model': this.chatboxes});
             this.chatboxesview = new this.ChatBoxesView({'model': this.chatboxes});
 
 
-
             this.connection.addHandler(
             this.connection.addHandler(
-                    $.proxy(this.roster.subscribeToSuggestedItems, this.roster), 
+                    $.proxy(this.roster.subscribeToSuggestedItems, this.roster),
                     'http://jabber.org/protocol/rosterx', 'message', null);
                     'http://jabber.org/protocol/rosterx', 'message', null);
 
 
             this.connection.roster.registerCallback(
             this.connection.roster.registerCallback(
-                    $.proxy(this.roster.rosterHandler, this.roster), 
+                    $.proxy(this.roster.rosterHandler, this.roster),
                     null, 'presence', null);
                     null, 'presence', null);
 
 
             this.connection.roster.get($.proxy(function () {
             this.connection.roster.get($.proxy(function () {
@@ -1842,12 +1887,12 @@
                             }, this.roster), null, 'presence', null);
                             }, this.roster), null, 'presence', null);
 
 
                     this.connection.addHandler(
                     this.connection.addHandler(
-                            $.proxy(function (message) { 
+                            $.proxy(function (message) {
                                 this.chatboxesview.messageReceived(message);
                                 this.chatboxesview.messageReceived(message);
                                 return true;
                                 return true;
                             }, this), null, 'message', 'chat');
                             }, this), null, 'message', 'chat');
 
 
-                    // XMPP Status 
+                    // XMPP Status
                     this.xmppstatus = new this.XMPPStatus();
                     this.xmppstatus = new this.XMPPStatus();
                     this.xmppstatusview = new this.XMPPStatusView({
                     this.xmppstatusview = new this.XMPPStatusView({
                         'model': this.xmppstatus
                         'model': this.xmppstatus
@@ -1856,6 +1901,8 @@
 
 
             // Controlbox toggler
             // Controlbox toggler
             if ($toggle.length) {
             if ($toggle.length) {
+                $connecting.hide();
+                $toggle.show();
                 $toggle.bind('click', $.proxy(function (e) {
                 $toggle.bind('click', $.proxy(function (e) {
                     e.preventDefault();
                     e.preventDefault();
                     if ($("div#controlbox").is(':visible')) {
                     if ($("div#controlbox").is(':visible')) {