Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/candy-chat/candy.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Stadler <patrick.stadler@gmail.com>2011-10-14 13:06:06 +0400
committerPatrick Stadler <patrick.stadler@gmail.com>2011-10-14 13:06:06 +0400
commitb290debc70ea3a2bf78217804614aefea7b60b03 (patch)
tree180fb26e56af406f9b96404a6d0b6cda1e352983
parentef9a2527a061cfdd02b5294dbb95de00c68410a0 (diff)
parent49da72d8696ead340f353ac82a34a7588ac30d5d (diff)
Merge branch 'dev'v1.0.4
-rw-r--r--.gitmodules2
-rw-r--r--Makefile6
-rw-r--r--candy.bundle.js276
-rw-r--r--candy.min.js2
-rw-r--r--src/candy.js2
-rw-r--r--src/core.js46
-rw-r--r--src/core/action.js18
-rw-r--r--src/core/chatUser.js28
-rw-r--r--src/core/event.js55
-rw-r--r--src/util.js52
-rw-r--r--src/view.js2
-rw-r--r--src/view/event.js6
-rw-r--r--src/view/observer.js12
-rw-r--r--src/view/pane.js49
-rw-r--r--src/view/template.js6
15 files changed, 400 insertions, 162 deletions
diff --git a/.gitmodules b/.gitmodules
index 0c44b31..12b64fc 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -3,7 +3,7 @@
url = git://github.com/recurser/jquery-i18n.git
[submodule "libs/strophejs"]
path = libs/strophejs
- url = git@github.com:amiadogroup/strophejs.git
+ url = git://github.com/amiadogroup/strophejs.git
[submodule "libs/strophejs-plugins"]
path = libs/strophejs-plugins
url = git://github.com/metajack/strophejs-plugins.git
diff --git a/Makefile b/Makefile
index 602fb3c..93e6d1e 100644
--- a/Makefile
+++ b/Makefile
@@ -26,7 +26,7 @@ CANDY_LIBS_FILES = $(LIBS_DIR)/strophejs/strophe.js $(LIBS_DIR)/strophejs-plugin
CANDY_FILES_BUNDLE = $(CANDY_FILES:.js=.bundle)
CANDY_LIBS_FILES_BUNDLE = $(CANDY_LIBS_FILES:.js=.libs-bundle)
-all: bundle min libs libs-min
+all: bundle min
bundle: clean-bundle $(CANDY_FILES_BUNDLE)
@@ -47,7 +47,9 @@ else
@@echo "** Please set YUI_COMPRESSOR to the path to the jar file."
endif
-libs: clean-libs $(CANDY_LIBS_FILES_BUNDLE)
+libs: libs-bundle libs-min
+
+libs-bundle: clean-libs $(CANDY_LIBS_FILES_BUNDLE)
%.libs-bundle: %.js
@@echo -n "Bundling" $< "..."
diff --git a/candy.bundle.js b/candy.bundle.js
index 375ea91..6e42da3 100644
--- a/candy.bundle.js
+++ b/candy.bundle.js
@@ -29,7 +29,7 @@ var Candy = (function(self, $) {
*/
self.about = {
name: 'Candy',
- version: '1.0.3'
+ version: '1.0.4'
};
/** Function: init
@@ -86,6 +86,10 @@ Candy.Core = (function(self, Strophe, $) {
* Opened rooms, containing instances of Candy.Core.ChatRooms
*/
_rooms = {},
+ /** PrivateVariable: _anonymousConnection
+ * Set in <Candy.Core.connect> when jidOrHost doesn't contain a @-char.
+ */
+ _anonymousConnection = false,
/** PrivateVariable: _options
* Options:
* (Boolean) debug - Debug (Default: false)
@@ -145,7 +149,7 @@ Candy.Core = (function(self, Strophe, $) {
self.init = function(service, options) {
_service = service;
// Apply options
- $.extend(_options, options);
+ $.extend(true, _options, options);
// Enable debug logging
if(_options.debug) {
@@ -187,6 +191,7 @@ Candy.Core = (function(self, Strophe, $) {
* There are four different procedures to login:
* connect('JID', 'password') - Connect a registered user
* connect('domain') - Connect anonymously to the domain. The user should receive a random JID.
+ * connect('domain', null, 'nick') - Connect anonymously to the domain. The user should receive a random JID but with a nick set.
* connect('JID') - Show login form and prompt for password. JID input is hidden.
* connect() - Show login form and prompt for JID and password.
*
@@ -195,29 +200,38 @@ Candy.Core = (function(self, Strophe, $) {
*
* Parameters:
* (String) jidOrHost - JID or Host
- * (String) password - Password of the user
+ * (String) password - Password of the user
+ * (String) nick - Nick of the user. Set one if you want to anonymously connect but preset a nick. If jidOrHost is a domain
+ * and this param is not set, Candy will prompt for a nick.
*/
- self.connect = function(jidOrHost, password) {
+ self.connect = function(jidOrHost, password, nick) {
// Reset before every connection attempt to make sure reconnections work after authfail, alltabsclosed, ...
_connection.reset();
_registerEventHandlers();
+
+ _anonymousConnection = !_anonymousConnection ? jidOrHost && jidOrHost.indexOf("@") < 0 : true;
+
if(jidOrHost && password) {
// authentication
- _connection.connect(jidOrHost + '/' + Candy.about.name, password, Candy.Core.Event.Strophe.Connect);
+ _connection.connect(_getEscapedJidFromJid(jidOrHost) + '/' + Candy.about.name, password, Candy.Core.Event.Strophe.Connect);
_user = new self.ChatUser(jidOrHost, Strophe.getNodeFromJid(jidOrHost));
+ } else if(jidOrHost && nick) {
+ // anonymous connect
+ _connection.connect(_getEscapedJidFromJid(jidOrHost) + '/' + Candy.about.name, null, Candy.Core.Event.Strophe.Connect);
+ _user = new self.ChatUser(null, nick); // set jid to null because we'll later receive it
} else if(jidOrHost) {
- if(jidOrHost.indexOf("@") < 0) {
- // Not a JID, anonymous login
- _connection.connect(jidOrHost, null, Candy.Core.Event.Strophe.Connect);
- } else {
- // Most likely a JID, display login modal
- Candy.Core.Event.Login(jidOrHost);
- }
+ Candy.Core.Event.Login(jidOrHost);
} else {
// display login modal
Candy.Core.Event.Login();
}
};
+
+ _getEscapedJidFromJid = function(jid) {
+ var node = Strophe.getNodeFromJid(jid),
+ domain = Strophe.getDomainFromJid(jid);
+ return node ? Strophe.escapeNode(node) + '@' + domain : domain;
+ };
/** Function: attach
* Attach an already binded & connected session to the server
@@ -287,6 +301,16 @@ Candy.Core = (function(self, Strophe, $) {
return _rooms;
};
+ /** Function: isAnonymousConnection
+ * Returns true if <Candy.Core.connect> was first called with a domain instead of a jid as the first param.
+ *
+ * Returns:
+ * (Boolean)
+ */
+ self.isAnonymousConnection = function() {
+ return _anonymousConnection;
+ };
+
/** Function: getOptions
* Gets options
*
@@ -465,7 +489,7 @@ Candy.View = (function(self, $) {
* (Object) options - Options: see _options field (value passed here gets extended by the default value in _options field)
*/
self.init = function(container, options) {
- $.extend(_options, options);
+ $.extend(true, _options, options);
_setupTranslation(_options.language);
// Set path to emoticons
@@ -549,6 +573,56 @@ Candy.Util = (function(self, $){
self.jidToId = function(jid) {
return MD5.hexdigest(jid);
};
+
+ /** Function: escapeJid
+ * Escapes a jid (node & resource get escaped)
+ *
+ * See:
+ * XEP-0106
+ *
+ * Parameters:
+ * (String) jid - Jid
+ *
+ * Returns:
+ * (String) - escaped jid
+ */
+ self.escapeJid = function(jid) {
+ var node = Strophe.escapeNode(Strophe.getNodeFromJid(jid)),
+ domain = Strophe.getDomainFromJid(jid),
+ resource = Strophe.getResourceFromJid(jid);
+
+ jid = node + '@' + domain;
+ if (resource) {
+ jid += '/' + Strophe.escapeNode(resource);
+ }
+
+ return jid;
+ };
+
+ /** Function: unescapeJid
+ * Unescapes a jid (node & resource get unescaped)
+ *
+ * See:
+ * XEP-0106
+ *
+ * Parameters:
+ * (String) jid - Jid
+ *
+ * Returns:
+ * (String) - unescaped Jid
+ */
+ self.unescapeJid = function(jid) {
+ var node = Strophe.unescapeNode(Strophe.getNodeFromJid(jid)),
+ domain = Strophe.getDomainFromJid(jid),
+ resource = Strophe.getResourceFromJid(jid);
+
+ jid = node + '@' + domain;
+ if(resource) {
+ jid += '/' + Strophe.unescapeNode(resource);
+ }
+
+ return jid;
+ };
/** Function: crop
* Crop a string with the specified length
@@ -575,7 +649,7 @@ Candy.Util = (function(self, $){
self.setCookie = function(name, value, lifetime_days) {
var exp = new Date();
exp.setDate(new Date().getDate() + lifetime_days);
- document.cookie = name + '=' + value + ';expires=' + exp.toUTCString() + 'path=/';
+ document.cookie = name + '=' + value + ';expires=' + exp.toUTCString() + ';path=/';
};
/** Function: cookieExists
@@ -1120,20 +1194,16 @@ Candy.Core.Action = (function(self, Strophe, $) {
},
/** Function: GetJidIfAnonymous
- * On anonymous login, initially we don't know the jid and as a result, Candy.Core._user is not set.
- * Check if user is not set & set it if if necessary.
+ * On anonymous login, initially we don't know the jid and as a result, Candy.Core._user doesn't have a jid.
+ * Check if user doesn't have a jid and get it if necessary from the connection.
*/
GetJidIfAnonymous: function() {
- if (!Candy.Core.getUser()) {
+ if (!Candy.Core.getUser().getJid()) {
Candy.Core.log("[Jabber] Anonymous login");
- var connection = Candy.Core.getConnection(),
- nick = connection.stream_id,
- jid = connection.jid;
- Candy.Core.setUser(new Candy.Core.ChatUser(jid, nick));
+ Candy.Core.getUser().data.jid = Candy.Core.getConnection().jid;
}
},
-
/** Class: Candy.Core.Action.Jabber.Room
* Room-specific commands
*/
@@ -1190,7 +1260,7 @@ Candy.Core.Action = (function(self, Strophe, $) {
if(msg === '') {
return false;
}
- Candy.Core.getConnection().muc.message(roomJid, undefined, msg, type);
+ Candy.Core.getConnection().muc.message(Candy.Util.escapeJid(roomJid), undefined, msg, type);
return true;
},
@@ -1218,7 +1288,7 @@ Candy.Core.Action = (function(self, Strophe, $) {
privacyList = currentUser.getPrivacyList('ignore');
if (privacyList.length > 0) {
$.each(privacyList, function(index, jid) {
- iq.c('item', {type:'jid', value: jid, action: 'deny', order : index})
+ iq.c('item', {type:'jid', value: Candy.Util.escapeJid(jid), action: 'deny', order : index})
.c('message').up().up();
});
} else {
@@ -1245,7 +1315,7 @@ Candy.Core.Action = (function(self, Strophe, $) {
*/
UserAction: function(roomJid, userJid, type, reason) {
var iqId,
- itemObj = {nick: Strophe.getResourceFromJid(userJid)};
+ itemObj = {nick: Strophe.escapeNode(Strophe.getResourceFromJid(userJid))};
switch(type) {
case 'kick':
iqId = 'kick1';
@@ -1478,24 +1548,42 @@ Candy.Core.ChatUser = function(jid, nick, affiliation, role) {
* - nick
* - affiliation
* - role
+ * - privacyLists
+ * - customData to be used by e.g. plugins
*/
this.data = {
jid: jid,
- nick: nick,
+ nick: Strophe.unescapeNode(nick),
affiliation: affiliation,
role: role,
privacyLists: {},
customData: {}
};
-
+
/** Function: getJid
- * Gets user jid
+ * Gets an unescaped user jid
+ *
+ * See:
+ * <Candy.Util.unescapeJid>
*
* Returns:
* (String) - jid
*/
this.getJid = function() {
- return this.data.jid;
+ return Candy.Util.unescapeJid(this.data.jid);
+ };
+
+ /** Function: getEscapedJid
+ * Escapes the user's jid (node & resource get escaped)
+ *
+ * See:
+ * <Candy.Util.escapeJid>
+ *
+ * Returns:
+ * (String) - escaped jid
+ */
+ this.getEscapedJid = function() {
+ return Candy.Util.escapeJid(this.data.jid);
};
/** Function: getNick
@@ -1505,7 +1593,7 @@ Candy.Core.ChatUser = function(jid, nick, affiliation, role) {
* (String) - nick
*/
this.getNick = function() {
- return this.data.nick;
+ return Strophe.unescapeNode(this.data.nick);
};
/** Function: getRole
@@ -1944,7 +2032,7 @@ Candy.Core.Event = (function(self, Strophe, $, observable) {
*/
Presence: function(msg) {
Candy.Core.log('[Jabber:Room] Presence');
- var from = msg.attr('from'),
+ var from = Candy.Util.unescapeJid(msg.attr('from')),
roomJid = Strophe.getBareJidFromJid(from),
presenceType = msg.attr('type');
@@ -1967,17 +2055,18 @@ Candy.Core.Event = (function(self, Strophe, $, observable) {
Candy.Core.getRooms()[roomJid] = new Candy.Core.ChatRoom(roomJid);
room = Candy.Core.getRoom(roomJid);
}
- // Room existed but user was not registered
- if(room.getUser() === null) {
- room.setUser(Candy.Core.getUser());
- }
var roster = room.getRoster(),
action, user,
item = msg.find('item');
// User joined a room
if(presenceType !== 'unavailable') {
- user = new Candy.Core.ChatUser(from, Strophe.getResourceFromJid(from), item.attr('affiliation'), item.attr('role'));
+ var nick = Strophe.getResourceFromJid(from);
+ user = new Candy.Core.ChatUser(from, nick, item.attr('affiliation'), item.attr('role'));
+ // Room existed but client (myself) is not yet registered
+ if(room.getUser() === null && Candy.Core.getUser().getNick() === nick) {
+ room.setUser(user);
+ }
roster.add(user);
action = 'join';
// User left a room
@@ -2013,29 +2102,43 @@ Candy.Core.Event = (function(self, Strophe, $, observable) {
// Room subject
var roomJid, message;
if(msg.children('subject').length > 0) {
- roomJid = Strophe.getBareJidFromJid(msg.attr('from'));
+ roomJid = Candy.Util.unescapeJid(Strophe.getBareJidFromJid(msg.attr('from')));
message = { name: Strophe.getNodeFromJid(roomJid), body: msg.children('subject').text(), type: 'subject' };
// Error messsage
} else if(msg.attr('type') === 'error') {
var error = msg.children('error');
if(error.attr('code') === '500' && error.children('text').length > 0) {
roomJid = msg.attr('from');
- message = { type: 'error', body: error.children('text').text() };
+ message = { type: 'info', body: error.children('text').text() };
}
- // Private chat message
- } else if(msg.attr('type') === 'chat') {
- roomJid = msg.attr('from');
- var bareRoomJid = Strophe.getBareJidFromJid(roomJid),
- // if a 3rd-party client sends a direct message to this user (not via the room) then the username is the node and not the resource.
- isNoConferenceRoomJid = !Candy.Core.getRoom(bareRoomJid),
- name = isNoConferenceRoomJid ? Strophe.getNodeFromJid(roomJid) : Strophe.getResourceFromJid(roomJid);
- message = { name: name, body: msg.children('body').text(), type: msg.attr('type'), isNoConferenceRoomJid: isNoConferenceRoomJid };
- // Multi-user chat message
+ // Chat message
+ } else if(msg.children('body').length > 0) {
+ // Private chat message
+ if(msg.attr('type') === 'chat') {
+ roomJid = Candy.Util.unescapeJid(msg.attr('from'));
+ var bareRoomJid = Strophe.getBareJidFromJid(roomJid),
+ // if a 3rd-party client sends a direct message to this user (not via the room) then the username is the node and not the resource.
+ isNoConferenceRoomJid = !Candy.Core.getRoom(bareRoomJid),
+ name = isNoConferenceRoomJid ? Strophe.getNodeFromJid(roomJid) : Strophe.getResourceFromJid(roomJid);
+ message = { name: name, body: msg.children('body').text(), type: msg.attr('type'), isNoConferenceRoomJid: isNoConferenceRoomJid };
+ // Multi-user chat message
+ } else {
+ roomJid = Candy.Util.unescapeJid(Strophe.getBareJidFromJid(msg.attr('from')));
+ var resource = Strophe.getResourceFromJid(msg.attr('from'));
+ // Message from a user
+ if(resource) {
+ resource = Strophe.unescapeNode(resource);
+ message = { name: resource, body: msg.children('body').text(), type: msg.attr('type') };
+ // Message from server (XEP-0045#registrar-statuscodes)
+ } else {
+ message = { name: '', body: msg.children('body').text(), type: 'info' };
+ }
+ }
+ // Unhandled message
} else {
- roomJid = Strophe.getBareJidFromJid(msg.attr('from'));
- message = { name: Strophe.getResourceFromJid(msg.attr('from')), body: msg.children('body').text(), type: msg.attr('type') };
+ return true;
}
-
+
// besides the delayed delivery (XEP-0203), there exists also XEP-0091 which is the legacy delayed delivery.
// the x[xmlns=jabber:x:delay] is the format in XEP-0091.
var delay = msg.children('delay') ? msg.children('delay') : msg.children('x[xmlns="' + Strophe.NS.DELAY +'"]'),
@@ -2209,13 +2312,13 @@ Candy.View.Event = (function(self, $) {
* Called before a new message will be shown.
*
* Parameters:
- * (String) message - parsed message
+ * (Object) args - {roomJid, nick, message}
*
* Returns:
* (String) message
*/
- beforeShow: function(message) {
- return message;
+ beforeShow: function(args) {
+ return args.message;
},
/** Function: onShow
@@ -2282,7 +2385,7 @@ Candy.View.Observer = (function(self, $) {
case Strophe.Status.AUTHENTICATING:
Candy.View.Pane.Chat.Modal.show($.i18n._('statusConnecting'), false, true);
break;
-
+
case Strophe.Status.ATTACHED:
case Strophe.Status.CONNECTED:
Candy.View.Pane.Chat.Modal.show($.i18n._('statusConnected'));
@@ -2297,7 +2400,7 @@ Candy.View.Observer = (function(self, $) {
Candy.View.Pane.Chat.Modal.showLoginForm($.i18n._('statusDisconnected'));
Candy.View.Event.Chat.onDisconnect();
break;
-
+
case Strophe.Status.AUTHFAIL:
Candy.View.Pane.Chat.Modal.showLoginForm($.i18n._('statusAuthfail'));
Candy.View.Event.Chat.onAuthfail();
@@ -2375,7 +2478,7 @@ Candy.View.Observer = (function(self, $) {
}
}
},
-
+
/** Function: notifyPrivateChats
* Notify private user chats if existing
*
@@ -2408,8 +2511,12 @@ Candy.View.Observer = (function(self, $) {
*/
update: function(obj, args) {
if(args.message.type === 'subject') {
+ if (!Candy.View.Pane.Chat.rooms[args.roomJid]) {
+ Candy.View.Pane.Room.init(args.roomJid, args.message.name);
+ Candy.View.Pane.Room.show(args.roomJid);
+ }
Candy.View.Pane.Room.setSubject(args.roomJid, args.message.body);
- } else if(args.message.type === 'error') {
+ } else if(args.message.type === 'info') {
Candy.View.Pane.Chat.infoMessage(args.roomJid, args.message.body);
} else {
// Initialize room if it's a message for a new private user chat
@@ -3001,8 +3108,8 @@ Candy.View.Pane = (function(self, $) {
*/
hideCloseControl: function() {
$('#admin-message-cancel').hide().click(function() {});
- },
-
+ },
+
/** Function: showLoginForm
* Show the login form modal
*
@@ -3014,23 +3121,30 @@ Candy.View.Pane = (function(self, $) {
Candy.View.Pane.Chat.Modal.show((message ? message : '') + Mustache.to_html(Candy.View.Template.Login.form, {
_labelUsername: $.i18n._('labelUsername'),
_labelPassword: $.i18n._('labelPassword'),
- _loginSubmit : $.i18n._('loginSubmit'),
- presetJid : (presetJid ? presetJid : false)
+ _loginSubmit: $.i18n._('loginSubmit'),
+ displayPassword: !Candy.Core.isAnonymousConnection(),
+ displayUsername: Candy.Core.isAnonymousConnection() || !presetJid,
+ presetJid: presetJid ? presetJid : false
}));
// register submit handler
$('#login-form').submit(function(event) {
var username = $('#username').val(),
- password = $('#password').val(),
+ password = $('#password').val();
+
+ if (!Candy.Core.isAnonymousConnection()) {
// guess the input and create a jid out of it
- jid = Candy.Core.getUser() && username.indexOf("@") < 0 ?
+ var jid = Candy.Core.getUser() && username.indexOf("@") < 0 ?
username + '@' + Strophe.getDomainFromJid(Candy.Core.getUser().getJid()) : username;
-
- if(jid.indexOf("@") < 0 && !Candy.Core.getUser()) {
- Candy.View.Pane.Chat.Modal.showLoginForm($.i18n._('loginInvalid'));
- } else {
- //Candy.View.Pane.Chat.Modal.hide();
- Candy.Core.connect(jid, password);
+
+ if(jid.indexOf("@") < 0 && !Candy.Core.getUser()) {
+ Candy.View.Pane.Chat.Modal.showLoginForm($.i18n._('loginInvalid'));
+ } else {
+ //Candy.View.Pane.Chat.Modal.hide();
+ Candy.Core.connect(jid, password);
+ }
+ } else { // anonymous login
+ Candy.Core.connect(presetJid, null, username);
}
return false;
});
@@ -3369,8 +3483,7 @@ Candy.View.Pane = (function(self, $) {
roomJid: roomJid,
roomType: roomType,
form: {
- _messageSubmit: $.i18n._('messageSubmit'),
- _maxLength: Candy.View.getOptions().crop.message.body
+ _messageSubmit: $.i18n._('messageSubmit')
},
roster: {
_userOnline: $.i18n._('userOnline')
@@ -3777,7 +3890,7 @@ Candy.View.Pane = (function(self, $) {
userId : userId,
userJid: user.getJid(),
nick: user.getNick(),
- displayNick: Candy.Util.crop(user.getNick(), Candy.View.getOptions().crop.roster.nickname),
+ displayNick: Candy.Util.crop(user.getNick(), Candy.View.getOptions().crop.roster.displayNick),
role: user.getRole(),
affiliation: user.getAffiliation(),
me: currentUser !== undefined && user.getNick() === currentUser.getNick(),
@@ -3820,6 +3933,7 @@ Candy.View.Pane = (function(self, $) {
}
// user is in room but maybe the affiliation/role has changed
} else {
+ usercountDiff = 0;
userElem.replaceWith(html);
$('#user-' + roomId + '-' + userId).css({opacity: 1}).show();
}
@@ -3917,7 +4031,7 @@ Candy.View.Pane = (function(self, $) {
*/
submit: function(event) {
var roomType = Candy.View.Pane.Chat.rooms[Candy.View.getCurrent().roomJid].type,
- message = $(this).children('.field').val().substring(0, Candy.View.getOptions().crop.message.body);
+ message = $(this).children('.field').val().substring(0, 1000);
message = Candy.View.Event.Message.beforeSend(message);
@@ -3941,11 +4055,15 @@ Candy.View.Pane = (function(self, $) {
* (String) timestamp - [optional] Timestamp of the message, if not present, current date.
*/
show: function(roomJid, name, message, timestamp) {
- message = Candy.Util.Parser.all(message.substring(0, Candy.View.getOptions().crop.message.body));
- message = Candy.View.Event.Message.beforeShow(message);
+ message = Candy.Util.Parser.all(message.substring(0, 1000));
+ message = Candy.View.Event.Message.beforeShow({'roomJid': roomJid, 'nick': name, 'message': message});
+ if(!message) {
+ return;
+ }
+
var html = Mustache.to_html(Candy.View.Template.Message.item, {
name: name,
- displayName: Candy.Util.crop(name, Candy.View.getOptions().crop.message.nickname),
+ displayName: Candy.Util.crop(name, Candy.View.getOptions().crop.message.displayName),
message: message,
time: Candy.Util.localizedTime(timestamp || new Date().toGMTString())
});
@@ -4025,7 +4143,7 @@ Candy.View.Template = (function(self){
self.Room = {
pane: '<div class="room-pane roomtype-{{roomType}}" id="chat-room-{{roomId}}" data-roomjid="{{roomJid}}" data-roomtype="{{roomType}}">{{> roster}}{{> messages}}{{> form}}</div>',
subject: '<dt>{{time}}</dt><dd class="subject"><span class="label">{{roomName}}</span>{{_roomSubject}} {{subject}}</dd>',
- form: '<div class="message-form-wrapper"></div><form method="post" class="message-form"><input name="message" class="field" type="text" autocomplete="off" maxlength="{{_maxLength}}" /><input type="submit" class="submit" name="submit" value="{{_messageSubmit}}" /></form>'
+ form: '<div class="message-form-wrapper"></div><form method="post" class="message-form"><input name="message" class="field" type="text" autocomplete="off" maxlength="1000" /><input type="submit" class="submit" name="submit" value="{{_messageSubmit}}" /></form>'
};
self.Roster = {
@@ -4040,9 +4158,9 @@ Candy.View.Template = (function(self){
self.Login = {
form: '<form method="post" id="login-form" class="login-form">'
- + '{{^presetJid}}<label for="username">{{_labelUsername}}</label><input type="text" id="username" name="username"/>{{/presetJid}}'
+ + '{{#displayUsername}}<label for="username">{{_labelUsername}}</label><input type="text" id="username" name="username"/>{{/displayUsername}}'
+ '{{#presetJid}}<input type="hidden" id="username" name="username" value="{{presetJid}}"/>{{/presetJid}}'
- + '<label for="password">{{_labelPassword}}</label><input type="password" id="password" name="password" />'
+ + '{{#displayPassword}}<label for="password">{{_labelPassword}}</label><input type="password" id="password" name="password" />{{/displayPassword}}'
+ '<input type="submit" class="button" value="{{_loginSubmit}}" /></form>'
};
diff --git a/candy.min.js b/candy.min.js
index 1dfa5f5..f493ad6 100644
--- a/candy.min.js
+++ b/candy.min.js
@@ -1 +1 @@
-var Candy=(function(a,b){a.about={name:"Candy",version:"1.0.3"};a.init=function(c,d){a.View.init(b("#candy"),d.view);a.Core.init(c,d.core)};return a}(Candy||{},jQuery));Candy.Core=(function(k,d,e){var c=null,i=null,a=null,f={},j={autojoin:true,debug:false},b=function(l,m){d.addNamespace(l,m)},g=function(){b("PRIVATE","jabber:iq:private");b("BOOKMARKS","storage:bookmarks");b("PRIVACY","jabber:iq:privacy");b("DELAY","jabber:x:delay")},h=function(){c.addHandler(k.Event.Jabber.Version,d.NS.VERSION,"iq");c.addHandler(k.Event.Jabber.Presence,null,"presence");c.addHandler(k.Event.Jabber.Message,null,"message");c.addHandler(k.Event.Jabber.Bookmarks,d.NS.PRIVATE,"iq");c.addHandler(k.Event.Jabber.Room.Disco,d.NS.DISCO_INFO,"iq");c.addHandler(k.Event.Jabber.PrivacyList,d.NS.PRIVACY,"iq","result");c.addHandler(k.Event.Jabber.PrivacyListError,d.NS.PRIVACY,"iq","error")};k.init=function(l,m){i=l;e.extend(j,m);if(j.debug){k.log=function(o){try{if(typeof window.console!==undefined&&typeof window.console.log!==undefined){console.log(o)}}catch(n){}};k.log("[Init] Debugging enabled")}g();c=new d.Connection(i);c.rawInput=k.rawInput.bind(k);c.rawOutput=k.rawOutput.bind(k);window.onbeforeunload=k.onWindowUnload;if(e.browser.mozilla){e(document).keydown(function(n){if(n.which===27){n.preventDefault()}})}};k.connect=function(m,l){c.reset();h();if(m&&l){c.connect(m+"/"+Candy.about.name,l,Candy.Core.Event.Strophe.Connect);a=new k.ChatUser(m,d.getNodeFromJid(m))}else{if(m){if(m.indexOf("@")<0){c.connect(m,null,Candy.Core.Event.Strophe.Connect)}else{Candy.Core.Event.Login(m)}}else{Candy.Core.Event.Login()}}};k.attach=function(m,l,n){a=new k.ChatUser(m,d.getNodeFromJid(m));h();c.attach(m,l,n,Candy.Core.Event.Strophe.Connect)};k.disconnect=function(){if(c.connected){e.each(k.getRooms(),function(){Candy.Core.Action.Jabber.Room.Leave(this.getJid())});c.disconnect()}};k.getUser=function(){return a};k.setUser=function(l){a=l};k.getConnection=function(){return c};k.getRooms=function(){return f};k.getOptions=function(){return j};k.getRoom=function(l){if(f[l]){return f[l]}return null};k.onWindowUnload=function(){c.sync=true;k.disconnect();c.flush()};k.rawInput=function(l){this.log("RECV: "+l)};k.rawOutput=function(l){this.log("SENT: "+l)};k.log=function(){};return k}(Candy.Core||{},Strophe,jQuery));Candy.View=(function(i,b){var d={container:null,roomJid:null},h={language:"en",resources:"res/",messages:{limit:2000,remove:500},crop:{message:{nickname:15,body:1000},roster:{nickname:15}}},a=function(j){b.i18n.setDictionary(i.Translation[j])},g=function(){Candy.Core.Event.addObserver(Candy.Core.Event.KEYS.CHAT,i.Observer.Chat);Candy.Core.Event.addObserver(Candy.Core.Event.KEYS.PRESENCE,i.Observer.Presence);Candy.Core.Event.addObserver(Candy.Core.Event.KEYS.MESSAGE,i.Observer.Message);Candy.Core.Event.addObserver(Candy.Core.Event.KEYS.LOGIN,i.Observer.Login)},e=function(){if(b.browser.msie&&!b.browser.version.match("^9")){b(document).focusin(Candy.View.Pane.Window.onFocus).focusout(Candy.View.Pane.Window.onBlur)}else{b(window).focus(Candy.View.Pane.Window.onFocus).blur(Candy.View.Pane.Window.onBlur)}b(window).resize(Candy.View.Pane.Chat.fitTabs)},f=function(){b("#emoticons-icon").click(function(j){i.Pane.Chat.Context.showEmoticonsMenu(j.currentTarget);j.stopPropagation()});b("#chat-autoscroll-control").click(Candy.View.Pane.Chat.Toolbar.onAutoscrollControlClick);b("#chat-sound-control").click(Candy.View.Pane.Chat.Toolbar.onSoundControlClick);if(Candy.Util.cookieExists("candy-nosound")){b("#chat-sound-control").click()}b("#chat-statusmessage-control").click(Candy.View.Pane.Chat.Toolbar.onStatusMessageControlClick);if(Candy.Util.cookieExists("candy-nostatusmessages")){b("#chat-statusmessage-control").click()}},c=function(){b("body").delegate("li[data-tooltip]","mouseenter",Candy.View.Pane.Chat.Tooltip.show)};i.init=function(j,k){b.extend(h,k);a(h.language);Candy.Util.Parser.setEmoticonPath(this.getOptions().resources+"img/emoticons/");d.container=j;d.container.html(Mustache.to_html(Candy.View.Template.Chat.pane,{tooltipEmoticons:b.i18n._("tooltipEmoticons"),tooltipSound:b.i18n._("tooltipSound"),tooltipAutoscroll:b.i18n._("tooltipAutoscroll"),tooltipStatusmessage:b.i18n._("tooltipStatusmessage"),tooltipAdministration:b.i18n._("tooltipAdministration"),tooltipUsercount:b.i18n._("tooltipUsercount"),resourcesPath:this.getOptions().resources},{tabs:Candy.View.Template.Chat.tabs,rooms:Candy.View.Template.Chat.rooms,modal:Candy.View.Template.Chat.modal,toolbar:Candy.View.Template.Chat.toolbar,soundcontrol:Candy.View.Template.Chat.soundcontrol}));e();f();g();c()};i.getCurrent=function(){return d};i.getOptions=function(){return h};return i}(Candy.View||{},jQuery));Candy.Util=(function(a,b){a.jidToId=function(c){return MD5.hexdigest(c)};a.crop=function(d,c){if(d.length>c){d=d.substr(0,c-3)+"..."}return d};a.setCookie=function(c,e,d){var f=new Date();f.setDate(new Date().getDate()+d);document.cookie=c+"="+e+";expires="+f.toUTCString()+"path=/"};a.cookieExists=function(c){return document.cookie.indexOf(c)>-1};a.getCookie=function(c){if(document.cookie){var d=new RegExp(escape(c)+"=([^;]*)","gm"),e=d.exec(document.cookie);if(e){return e[1]}}};a.deleteCookie=function(c){document.cookie=c+"=;expires=Thu, 01-Jan-70 00:00:01 GMT"};a.getPosLeftAccordingToWindowBounds=function(e,h){var d=b(document).width(),c=e.outerWidth(),f=c-e.outerWidth(true),g="left";if(h+c>=d){h-=c-f;g="right"}return{px:h,backgroundPositionAlignment:g}};a.getPosTopAccordingToWindowBounds=function(d,h){var g=b(document).height(),c=d.outerHeight(),e=c-d.outerHeight(true),f="top";if(h+c>=g){h-=c-e;f="bottom"}return{px:h,backgroundPositionAlignment:f}};a.localizedTime=function(d){if(d===undefined){return undefined}var c=a.iso8601toDate(d);if(c.toDateString()===new Date().toDateString()){return c.format(b.i18n._("timeFormat"))}else{return c.format(b.i18n._("dateFormat"))}};a.iso8601toDate=function(c){var e=Date.parse(c),d=0;if(isNaN(e)){var f=/^(\d{4}|[+\-]\d{6})-(\d{2})-(\d{2})(?:[T ](\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3,}))?)?(?:(Z)|([+\-])(\d{2})(?::?(\d{2}))?))?/.exec(c);if(f){if(f[8]!=="Z"){d=+f[10]*60+(+f[11]);if(f[9]==="+"){d=-d}}return new Date(+f[1],+f[2]-1,+f[3],+f[4],+f[5]+d,+f[6],f[7]?+f[7].substr(0,3):0)}else{e=Date.parse(c.replace(/^(\d{4})(\d{2})(\d{2})/,"$1-$2-$3")+"Z")}}return new Date(e)};a.isEmptyObject=function(c){var d;for(d in c){if(c.hasOwnProperty(d)){return false}}return true};a.forceRedraw=function(c){c.css({display:"none"});setTimeout(function(){this.css({display:"block"})}.bind(c),1)};a.Parser={_emoticonPath:"",setEmoticonPath:function(c){this._emoticonPath=c},emoticons:[{plain:":)",regex:/((\s):-?\)|:-?\)(\s|$))/gm,image:"Smiling.png"},{plain:";)",regex:/((\s);-?\)|;-?\)(\s|$))/gm,image:"Winking.png"},{plain:":D",regex:/((\s):-?D|:-?D(\s|$))/gm,image:"Grinning.png"},{plain:";D",regex:/((\s);-?D|;-?D(\s|$))/gm,image:"Grinning_Winking.png"},{plain:":(",regex:/((\s):-?\(|:-?\((\s|$))/gm,image:"Unhappy.png"},{plain:"^^",regex:/((\s)\^\^|\^\^(\s|$))/gm,image:"Happy_3.png"},{plain:":P",regex:/((\s):-?P|:-?P(\s|$))/igm,image:"Tongue_Out.png"},{plain:";P",regex:/((\s);-?P|;-?P(\s|$))/igm,image:"Tongue_Out_Winking.png"},{plain:":S",regex:/((\s):-?S|:-?S(\s|$))/igm,image:"Confused.png"},{plain:":/",regex:/((\s):-?\/|:-?\/(\s|$))/gm,image:"Uncertain.png"},{plain:"8)",regex:/((\s)8-?\)|8-?\)(\s|$))/gm,image:"Sunglasses.png"},{plain:"$)",regex:/((\s)\$-?\)|\$-?\)(\s|$))/gm,image:"Greedy.png"},{plain:"oO",regex:/((\s)oO|oO(\s|$))/gm,image:"Huh.png"},{plain:":x",regex:/((\s):x|:x(\s|$))/gm,image:"Lips_Sealed.png"},{plain:":666:",regex:/((\s):666:|:666:(\s|$))/gm,image:"Devil.png"},{plain:"<3",regex:/((\s)&lt;3|&lt;3(\s|$))/gm,image:"Heart.png"}],emotify:function(d){var c;for(c=this.emoticons.length-1;c>=0;c--){d=d.replace(this.emoticons[c].regex,'$2<img class="emoticon" alt="$1" src="'+this._emoticonPath+this.emoticons[c].image+'" />$3')}return d},linkify:function(c){c=c.replace(/(^|[^\/])(www\.[^\.]+\.[\S]+(\b|$))/gi,"$1http://$2");return c.replace(/(\b(https?|ftp|file):\/\/[\-A-Z0-9+&@#\/%?=~_|!:,.;]*[\-A-Z0-9+&@#\/%=~_|])/ig,'<a href="$1" target="_blank">$1</a>')},escape:function(c){return b("<div/>").text(c).html()},all:function(c){if(c){c=this.escape(c);c=this.linkify(c);c=this.emotify(c)}return c}};return a}(Candy.Util||{},jQuery));Candy.Util.Observable=(function(a){var b={};a.addObserver=function(c,d){if(b[c]===undefined){b[c]=[]}b[c].push(d)};a.deleteObserver=function(c,d){delete b[c][d]};a.clearObservers=function(c){if(c!==undefined){b[c]=[]}else{b={}}};a.notifyObservers=function(f,c){var d=b[f],e;for(e=d.length-1;e>=0;e--){d[e].update(a,c)}};return a}(Candy.Util.Observable||{}));Candy.Core.Action=(function(a,c,b){a.Jabber={Version:function(d){Candy.Core.getConnection().send($iq({type:"result",to:d.attr("from"),from:d.attr("to"),id:d.attr("id")}).c("query",{name:Candy.about.name,version:Candy.about.version,os:navigator.userAgent}))},Roster:function(){Candy.Core.getConnection().send($iq({type:"get",xmlns:c.NS.CLIENT}).c("query",{xmlns:c.NS.ROSTER}).tree())},Presence:function(d){Candy.Core.getConnection().send($pres(d).tree())},Services:function(){Candy.Core.getConnection().send($iq({type:"get",xmlns:c.NS.CLIENT}).c("query",{xmlns:c.NS.DISCO_ITEMS}).tree())},Autojoin:function(){if(Candy.Core.getOptions().autojoin===true){Candy.Core.getConnection().send($iq({type:"get",xmlns:c.NS.CLIENT}).c("query",{xmlns:c.NS.PRIVATE}).c("storage",{xmlns:c.NS.BOOKMARKS}).tree())}else{if(b.isArray(Candy.Core.getOptions().autojoin)){b.each(Candy.Core.getOptions().autojoin,function(){a.Jabber.Room.Join(this.valueOf())})}}},ResetIgnoreList:function(){Candy.Core.getConnection().send($iq({type:"set",from:Candy.Core.getUser().getJid(),id:"set1"}).c("query",{xmlns:c.NS.PRIVACY}).c("list",{name:"ignore"}).c("item",{action:"allow",order:"0"}).tree())},RemoveIgnoreList:function(){Candy.Core.getConnection().send($iq({type:"set",from:Candy.Core.getUser().getJid(),id:"remove1"}).c("query",{xmlns:c.NS.PRIVACY}).c("list",{name:"ignore"}).tree())},GetIgnoreList:function(){Candy.Core.getConnection().send($iq({type:"get",from:Candy.Core.getUser().getJid(),id:"get1"}).c("query",{xmlns:c.NS.PRIVACY}).c("list",{name:"ignore"}).tree())},SetIgnoreListActive:function(){Candy.Core.getConnection().send($iq({type:"set",from:Candy.Core.getUser().getJid(),id:"set2"}).c("query",{xmlns:c.NS.PRIVACY}).c("active",{name:"ignore"}).tree())},GetJidIfAnonymous:function(){if(!Candy.Core.getUser()){Candy.Core.log("[Jabber] Anonymous login");var e=Candy.Core.getConnection(),d=e.stream_id,f=e.jid;Candy.Core.setUser(new Candy.Core.ChatUser(f,d))}},Room:{Join:function(d){a.Jabber.Room.Disco(d);Candy.Core.getConnection().muc.join(d,Candy.Core.getUser().getNick())},Leave:function(d){Candy.Core.getConnection().muc.leave(d,Candy.Core.getRoom(d).getUser().getNick(),function(){})},Disco:function(d){Candy.Core.getConnection().send($iq({type:"get",from:Candy.Core.getUser().getJid(),to:d,id:"disco3"}).c("query",{xmlns:c.NS.DISCO_INFO}).tree())},Message:function(d,f,e){f=b.trim(f);if(f===""){return false}Candy.Core.getConnection().muc.message(d,undefined,f,e);return true},IgnoreUnignore:function(d){Candy.Core.getUser().addToOrRemoveFromPrivacyList("ignore",d);Candy.Core.Action.Jabber.Room.UpdatePrivacyList()},UpdatePrivacyList:function(){var d=Candy.Core.getUser(),f=$iq({type:"set",from:d.getJid(),id:"edit1"}).c("query",{xmlns:"jabber:iq:privacy"}).c("list",{name:"ignore"}),e=d.getPrivacyList("ignore");if(e.length>0){b.each(e,function(g,h){f.c("item",{type:"jid",value:h,action:"deny",order:g}).c("message").up().up()})}else{f.c("item",{action:"allow",order:"0"})}Candy.Core.getConnection().send(f.tree())},Admin:{UserAction:function(d,i,g,h){var f,e={nick:c.getResourceFromJid(i)};switch(g){case"kick":f="kick1";e.role="none";break;case"ban":f="ban1";e.affiliation="outcast";break;default:return false}Candy.Core.getConnection().send($iq({type:"set",from:Candy.Core.getUser().getJid(),to:d,id:f}).c("query",{xmlns:c.NS.MUC_ADMIN}).c("item",e).c("reason").t(h).tree());return true},SetSubject:function(d,e){Candy.Core.getConnection().muc.setTopic(d,e)}}}};return a}(Candy.Core.Action||{},Strophe,jQuery));Candy.Core.ChatRoom=function(a){this.room={jid:a,name:null};this.user=null;this.roster=new Candy.Core.ChatRoster();this.setUser=function(b){this.user=b};this.getUser=function(){return this.user};this.getJid=function(){return this.room.jid};this.setName=function(b){this.room.name=b};this.getName=function(){return this.room.name};this.setRoster=function(b){this.roster=b};this.getRoster=function(){return this.roster}};Candy.Core.ChatRoster=function(){this.items={};this.add=function(a){this.items[a.getJid()]=a};this.remove=function(a){delete this.items[a]};this.get=function(a){return this.items[a]};this.getAll=function(){return this.items}};Candy.Core.ChatUser=function(b,a,c,d){this.ROLE_MODERATOR="moderator";this.AFFILIATION_OWNER="owner";this.data={jid:b,nick:a,affiliation:c,role:d,privacyLists:{},customData:{}};this.getJid=function(){return this.data.jid};this.getNick=function(){return this.data.nick};this.getRole=function(){return this.data.role};this.getAffiliation=function(){return this.data.affiliation};this.isModerator=function(){return this.getRole()===this.ROLE_MODERATOR||this.getAffiliation()===this.AFFILIATION_OWNER};this.addToOrRemoveFromPrivacyList=function(g,f){if(!this.data.privacyLists[g]){this.data.privacyLists[g]=[]}var e=-1;if((e=this.data.privacyLists[g].indexOf(f))!==-1){this.data.privacyLists[g].splice(e,1)}else{this.data.privacyLists[g].push(f)}return this.data.privacyLists[g]};this.getPrivacyList=function(e){if(!this.data.privacyLists[e]){this.data.privacyLists[e]=[]}return this.data.privacyLists[e]};this.isInPrivacyList=function(f,e){if(!this.data.privacyLists[f]){return false}return this.data.privacyLists[f].indexOf(e)!==-1};this.setCustomData=function(e){this.data.customData=e};this.getCustomData=function(){return this.data.customData}};Candy.Core.Event=(function(a,e,c,d){var b;for(b in d){if(d.hasOwnProperty(b)){a[b]=d[b]}}a.KEYS={CHAT:1,PRESENCE:2,MESSAGE:3,LOGIN:4};a.Strophe={Connect:function(f){switch(f){case e.Status.CONNECTED:Candy.Core.log("[Connection] Connected");Candy.Core.Action.Jabber.GetJidIfAnonymous();case e.Status.ATTACHED:Candy.Core.log("[Connection] Attached");Candy.Core.Action.Jabber.Presence();Candy.Core.Action.Jabber.Autojoin();Candy.Core.Action.Jabber.GetIgnoreList();break;case e.Status.DISCONNECTED:Candy.Core.log("[Connection] Disconnected");break;case e.Status.AUTHFAIL:Candy.Core.log("[Connection] Authentication failed");break;case e.Status.CONNECTING:Candy.Core.log("[Connection] Connecting");break;case e.Status.DISCONNECTING:Candy.Core.log("[Connection] Disconnecting");break;case e.Status.AUTHENTICATING:Candy.Core.log("[Connection] Authenticating");break;case e.Status.ERROR:case e.Status.CONNFAIL:Candy.Core.log("[Connection] Failed ("+f+")");break;default:Candy.Core.log("[Connection] What?!");break}a.notifyObservers(a.KEYS.CHAT,{type:"connection",status:f})}};a.Login=function(f){a.notifyObservers(a.KEYS.LOGIN,{presetJid:f})};a.Jabber={Version:function(f){Candy.Core.log("[Jabber] Version");Candy.Core.Action.Jabber.Version(c(f));return true},Presence:function(f){Candy.Core.log("[Jabber] Presence");f=c(f);if(f.children('x[xmlns^="'+e.NS.MUC+'"]').length>0){a.Jabber.Room.Presence(f)}return true},Bookmarks:function(f){Candy.Core.log("[Jabber] Bookmarks");c("conference",f).each(function(){var g=c(this);if(g.attr("autojoin")){Candy.Core.Action.Jabber.Room.Join(g.attr("jid"))}});return true},PrivacyList:function(g){Candy.Core.log("[Jabber] PrivacyList");var f=Candy.Core.getUser();c('list[name="ignore"] item',g).each(function(){var h=c(this);if(h.attr("action")==="deny"){f.addToOrRemoveFromPrivacyList("ignore",h.attr("value"))}});Candy.Core.Action.Jabber.SetIgnoreListActive();return false},PrivacyListError:function(f){Candy.Core.log("[Jabber] PrivacyListError");if(c('error[code="404"][type="cancel"] item-not-found',f)){Candy.Core.Action.Jabber.ResetIgnoreList();Candy.Core.Action.Jabber.SetIgnoreListActive()}return false},Message:function(i){Candy.Core.log("[Jabber] Message");var i=c(i),h=i.attr("from"),g=i.attr("type"),f=i.attr("to");if(h!==e.getDomainFromJid(h)&&(g==="groupchat"||g==="chat"||g==="error")){a.Jabber.Room.Message(i)}else{if(!f&&h===e.getDomainFromJid(h)){a.notifyObservers(a.KEYS.CHAT,{type:(g||"message"),message:i.children("body").text()})}else{if(f&&h===e.getDomainFromJid(h)){a.notifyObservers(a.KEYS.CHAT,{type:(g||"message"),subject:i.children("subject").text(),message:i.children("body").text()})}}}return true},Room:{Leave:function(f){Candy.Core.log("[Jabber:Room] Leave");var f=c(f),l=f.attr("from"),n=e.getBareJidFromJid(l),j=Candy.Core.getRoom(n).getName(),m=f.find("item"),k="leave",i,h;delete Candy.Core.getRooms()[n];if(m.attr("role")==="none"){if(f.find("status").attr("code")==="307"){k="kick"}else{if(f.find("status").attr("code")==="301"){k="ban"}}i=m.find("reason").text();h=m.find("actor").attr("jid")}var g=new Candy.Core.ChatUser(l,e.getResourceFromJid(l),m.attr("affiliation"),m.attr("role"));a.notifyObservers(a.KEYS.PRESENCE,{roomJid:n,roomName:j,type:k,reason:i,actor:h,user:g});return true},Disco:function(i){Candy.Core.log("[Jabber:Room] Disco");var i=c(i),g=e.getBareJidFromJid(i.attr("from"));if(!Candy.Core.getRooms()[g]){Candy.Core.getRooms()[g]=new Candy.Core.ChatRoom(g)}var f=i.find("identity").attr("name"),h=Candy.Core.getRoom(g);if(h.getName()===null){h.setName(f)}return true},Presence:function(g){Candy.Core.log("[Jabber:Room] Presence");var k=g.attr("from"),n=e.getBareJidFromJid(k),l=g.attr("type");if(e.getResourceFromJid(k)===Candy.Core.getUser().getNick()&&l==="unavailable"){a.Jabber.Room.Leave(g);return true}if(l==="error"){Candy.Core.log("[Jabber:Room] Presence Error");delete Candy.Core.getRooms()[n];return true}var f=Candy.Core.getRoom(n);if(!f){Candy.Core.getRooms()[n]=new Candy.Core.ChatRoom(n);f=Candy.Core.getRoom(n)}if(f.getUser()===null){f.setUser(Candy.Core.getUser())}var j=f.getRoster(),h,i,m=g.find("item");if(l!=="unavailable"){i=new Candy.Core.ChatUser(k,e.getResourceFromJid(k),m.attr("affiliation"),m.attr("role"));j.add(i);h="join"}else{h="leave";if(m.attr("role")==="none"){if(g.find("status").attr("code")==="307"){h="kick"}else{if(g.find("status").attr("code")==="301"){h="ban"}}}i=j.get(k);j.remove(k)}a.notifyObservers(a.KEYS.PRESENCE,{roomJid:n,roomName:f.getName(),user:i,action:h,currentUser:Candy.Core.getUser()});return true},Message:function(h){Candy.Core.log("[Jabber:Room] Message");var n,m;if(h.children("subject").length>0){n=e.getBareJidFromJid(h.attr("from"));m={name:e.getNodeFromJid(n),body:h.children("subject").text(),type:"subject"}}else{if(h.attr("type")==="error"){var l=h.children("error");if(l.attr("code")==="500"&&l.children("text").length>0){n=h.attr("from");m={type:"error",body:l.children("text").text()}}}else{if(h.attr("type")==="chat"){n=h.attr("from");var f=e.getBareJidFromJid(n),i=!Candy.Core.getRoom(f),g=i?e.getNodeFromJid(n):e.getResourceFromJid(n);m={name:g,body:h.children("body").text(),type:h.attr("type"),isNoConferenceRoomJid:i}}else{n=e.getBareJidFromJid(h.attr("from"));m={name:e.getResourceFromJid(h.attr("from")),body:h.children("body").text(),type:h.attr("type")}}}}var j=h.children("delay")?h.children("delay"):h.children('x[xmlns="'+e.NS.DELAY+'"]'),k=j!==undefined?j.attr("stamp"):null;a.notifyObservers(a.KEYS.MESSAGE,{roomJid:n,message:m,timestamp:k});return true}}};return a}(Candy.Core.Event||{},Strophe,jQuery,Candy.Util.Observable));Candy.View.Event=(function(a,b){a.Chat={onAdminMessage:function(c){return},onDisconnect:function(){return},onAuthfail:function(){return}};a.Room={onAdd:function(c){return},onShow:function(c){return},onHide:function(c){return},onSubjectChange:function(c){return},onClose:function(c){return},onPresenceChange:function(c){return}};a.Roster={onUpdate:function(c){return},onContextMenu:function(c){return{}},afterContextMenu:function(c){return}};a.Message={beforeShow:function(c){return c},onShow:function(c){return},beforeSend:function(c){return c}};return a}(Candy.View.Event||{},jQuery));Candy.View.Observer=(function(a,b){a.Chat={update:function(d,c){if(c.type==="connection"){switch(c.status){case Strophe.Status.CONNECTING:case Strophe.Status.AUTHENTICATING:Candy.View.Pane.Chat.Modal.show(b.i18n._("statusConnecting"),false,true);break;case Strophe.Status.ATTACHED:case Strophe.Status.CONNECTED:Candy.View.Pane.Chat.Modal.show(b.i18n._("statusConnected"));Candy.View.Pane.Chat.Modal.hide();break;case Strophe.Status.DISCONNECTING:Candy.View.Pane.Chat.Modal.show(b.i18n._("statusDisconnecting"),false,true);break;case Strophe.Status.DISCONNECTED:Candy.View.Pane.Chat.Modal.showLoginForm(b.i18n._("statusDisconnected"));Candy.View.Event.Chat.onDisconnect();break;case Strophe.Status.AUTHFAIL:Candy.View.Pane.Chat.Modal.showLoginForm(b.i18n._("statusAuthfail"));Candy.View.Event.Chat.onAuthfail();break;default:Candy.View.Pane.Chat.Modal.show(b.i18n._("status",c.status));break}}else{if(c.type==="message"){Candy.View.Pane.Chat.adminMessage((c.subject||""),c.message)}else{if(c.type==="chat"||c.type==="groupchat"){Candy.View.Pane.Chat.onInfoMessage(Candy.View.getCurrent().roomJid,(c.subject||""),c.message)}}}}};a.Presence={update:function(g,d){if(d.type==="leave"){var c=Candy.View.Pane.Room.getUser(d.roomJid);Candy.View.Pane.Room.close(d.roomJid);a.Presence.notifyPrivateChats(c,d.type)}else{if(d.type==="kick"||d.type==="ban"){var f=d.actor?Strophe.getNodeFromJid(d.actor):d.roomName,e;switch(d.type){case"kick":e=b.i18n._("youHaveBeenKickedBy",[d.roomName,f]);break;case"ban":e=b.i18n._("youHaveBeenBannedBy",[d.roomName,f]);break}Candy.View.Pane.Chat.Modal.show(Mustache.to_html(Candy.View.Template.Chat.Context.adminMessageReason,{reason:d.reason,_action:e,_reason:b.i18n._("reasonWas",[d.reason])}));setTimeout(function(){Candy.View.Pane.Chat.Modal.hide(function(){Candy.View.Pane.Room.close(d.roomJid);a.Presence.notifyPrivateChats(d.user,d.type)})},5000);Candy.View.Event.Room.onPresenceChange({type:d.type,reason:d.reason,roomJid:d.roomJid,user:d.user})}else{if(!Candy.View.Pane.Chat.rooms[d.roomJid]){Candy.View.Pane.Room.init(d.roomJid,d.roomName);Candy.View.Pane.Room.show(d.roomJid)}Candy.View.Pane.Roster.update(d.roomJid,d.user,d.action,d.currentUser);if(Candy.View.Pane.Chat.rooms[d.user.getJid()]){Candy.View.Pane.Roster.update(d.user.getJid(),d.user,d.action,d.currentUser);Candy.View.Pane.PrivateRoom.setStatus(d.user.getJid(),d.action)}}}},notifyPrivateChats:function(d,e){Candy.Core.log("[View:Observer] notify Private Chats");var c;for(c in Candy.View.Pane.Chat.rooms){if(Candy.View.Pane.Chat.rooms.hasOwnProperty(c)&&Candy.View.Pane.Room.getUser(c)&&d.getJid()===Candy.View.Pane.Room.getUser(c).getJid()){Candy.View.Pane.Roster.update(c,d,e,d);Candy.View.Pane.PrivateRoom.setStatus(c,e)}}}};a.Message={update:function(d,c){if(c.message.type==="subject"){Candy.View.Pane.Room.setSubject(c.roomJid,c.message.body)}else{if(c.message.type==="error"){Candy.View.Pane.Chat.infoMessage(c.roomJid,c.message.body)}else{if(c.message.type==="chat"&&!Candy.View.Pane.Chat.rooms[c.roomJid]){Candy.View.Pane.PrivateRoom.open(c.roomJid,c.message.name,false,c.message.isNoConferenceRoomJid)}Candy.View.Pane.Message.show(c.roomJid,c.message.name,c.message.body,c.timestamp)}}}};a.Login={update:function(d,c){Candy.View.Pane.Chat.Modal.showLoginForm(null,c.presetJid)}};return a}(Candy.View.Observer||{},jQuery));Candy.View.Pane=(function(a,b){a.Window={_hasFocus:true,_plainTitle:document.title,_unreadMessagesCount:0,autoscroll:true,hasFocus:function(){return a.Window._hasFocus},increaseUnreadMessages:function(){a.Window.renderUnreadMessages(++a.Window._unreadMessagesCount)},reduceUnreadMessages:function(c){a.Window._unreadMessagesCount-=c;if(a.Window._unreadMessagesCount<=0){a.Window.clearUnreadMessages()}else{a.Window.renderUnreadMessages(a.Window._unreadMessagesCount)}},clearUnreadMessages:function(){a.Window._unreadMessagesCount=0;document.title=a.Window._plainTitle},renderUnreadMessages:function(c){document.title=Candy.View.Template.Window.unreadmessages.replace("{{count}}",c).replace("{{title}}",a.Window._plainTitle)},onFocus:function(){a.Window._hasFocus=true;if(Candy.View.getCurrent().roomJid){a.Room.setFocusToForm(Candy.View.getCurrent().roomJid);a.Chat.clearUnreadMessages(Candy.View.getCurrent().roomJid)}},onBlur:function(){a.Window._hasFocus=false}};a.Chat={rooms:[],addTab:function(d,c,e){var h=Candy.Util.jidToId(d),f=Mustache.to_html(Candy.View.Template.Chat.tab,{roomJid:d,roomId:h,name:c||Strophe.getNodeFromJid(d),privateUserChat:function(){return e==="chat"},roomType:e}),g=b(f).appendTo("#chat-tabs");g.click(a.Chat.tabClick);b("a.close",g).click(a.Chat.tabClose);a.Chat.fitTabs()},getTab:function(c){return b("#chat-tabs").children('li[data-roomjid="'+c+'"]')},removeTab:function(c){a.Chat.getTab(c).remove();a.Chat.fitTabs()},setActiveTab:function(c){b("#chat-tabs").children().each(function(){var d=b(this);if(d.attr("data-roomjid")===c){d.addClass("active")}else{d.removeClass("active")}})},increaseUnreadMessages:function(d){var c=this.getTab(d).find(".unread");c.show().text(c.text()!==""?parseInt(c.text(),10)+1:1);if(a.Chat.rooms[d].type==="chat"){a.Window.increaseUnreadMessages()}},clearUnreadMessages:function(d){var c=a.Chat.getTab(d).find(".unread");a.Window.reduceUnreadMessages(c.text());c.hide().text("")},tabClick:function(d){var c=Candy.View.getCurrent().roomJid;a.Chat.rooms[c].scrollPosition=a.Room.getPane(c,".message-pane-wrapper").scrollTop();a.Room.show(b(this).attr("data-roomjid"));d.preventDefault()},tabClose:function(d){var c=b(this).parent().attr("data-roomjid");if(a.Chat.rooms[c].type==="chat"){a.Room.close(c)}else{Candy.Core.Action.Jabber.Room.Leave(c)}return false},allTabsClosed:function(){Candy.Core.disconnect();a.Chat.Toolbar.hide();return},fitTabs:function(){var g=b("#chat-tabs").innerWidth(),f=0,e=b("#chat-tabs").children();e.each(function(){f+=b(this).css({width:"auto",overflow:"visible"}).outerWidth(true)});if(f>g){var c=e.outerWidth(true)-e.width(),d=Math.floor((g)/e.length)-c;e.css({width:d,overflow:"hidden"})}},updateToolbar:function(c){b("#chat-toolbar").find(".context").click(function(d){a.Chat.Context.show(d.currentTarget,c);d.stopPropagation()});Candy.View.Pane.Chat.Toolbar.updateUsercount(Candy.View.Pane.Chat.rooms[c].usercount)},adminMessage:function(d,e){if(Candy.View.getCurrent().roomJid){var c=Mustache.to_html(Candy.View.Template.Chat.adminMessage,{subject:d,message:e,sender:b.i18n._("administratorMessageSubject"),time:Candy.Util.localizedTime(new Date().toGMTString())});b("#chat-rooms").children().each(function(){a.Room.appendToMessagePane(b(this).attr("data-roomjid"),c)});a.Room.scrollToBottom(Candy.View.getCurrent().roomJid);Candy.View.Event.Chat.onAdminMessage({subject:d,message:e})}},infoMessage:function(c,d,e){a.Chat.onInfoMessage(c,d,e)},onInfoMessage:function(c,e,f){if(Candy.View.getCurrent().roomJid){var d=Mustache.to_html(Candy.View.Template.Chat.infoMessage,{subject:e,message:b.i18n._(f),time:Candy.Util.localizedTime(new Date().toGMTString())});a.Room.appendToMessagePane(c,d);if(Candy.View.getCurrent().roomJid===c){a.Room.scrollToBottom(Candy.View.getCurrent().roomJid)}}},Toolbar:{show:function(){b("#chat-toolbar").show()},hide:function(){b("#chat-toolbar").hide()},playSound:function(){a.Chat.Toolbar.onPlaySound()},onPlaySound:function(){var c=document.getElementById("chat-sound-player");c.SetVariable("method:stop","");c.SetVariable("method:play","")},onSoundControlClick:function(){var c=b("#chat-sound-control");if(c.hasClass("checked")){a.Chat.Toolbar.playSound=function(){};Candy.Util.setCookie("candy-nosound","1",365)}else{a.Chat.Toolbar.playSound=function(){a.Chat.Toolbar.onPlaySound()};Candy.Util.deleteCookie("candy-nosound")}c.toggleClass("checked")},onAutoscrollControlClick:function(){var c=b("#chat-autoscroll-control");if(c.hasClass("checked")){a.Room.scrollToBottom=function(d){a.Room.onScrollToStoredPosition(d)};a.Window.autoscroll=false}else{a.Room.scrollToBottom=function(d){a.Room.onScrollToBottom(d)};a.Room.scrollToBottom(Candy.View.getCurrent().roomJid);a.Window.autoscroll=true}c.toggleClass("checked")},onStatusMessageControlClick:function(){var c=b("#chat-statusmessage-control");if(c.hasClass("checked")){a.Chat.infoMessage=function(){};Candy.Util.setCookie("candy-nostatusmessages","1",365)}else{a.Chat.infoMessage=function(d,e,f){a.Chat.onInfoMessage(d,e,f)};Candy.Util.deleteCookie("candy-nostatusmessages")}c.toggleClass("checked")},updateUsercount:function(c){b("#chat-usercount").text(c)}},Modal:{show:function(d,e,c){if(e){a.Chat.Modal.showCloseControl()}else{a.Chat.Modal.hideCloseControl()}if(c){a.Chat.Modal.showSpinner()}else{a.Chat.Modal.hideSpinner()}b("#chat-modal-body").html(d);b("#chat-modal").fadeIn("fast");b("#chat-modal-overlay").show()},hide:function(c){b("#chat-modal").fadeOut("fast",function(){b("#chat-modal-body").text("");b("#chat-modal-overlay").hide()});b(document).keydown(function(d){if(d.which===27){d.preventDefault()}});if(c){c()}},showSpinner:function(){b("#chat-modal-spinner").show()},hideSpinner:function(){b("#chat-modal-spinner").hide()},showCloseControl:function(){b("#admin-message-cancel").show().click(function(c){a.Chat.Modal.hide();c.preventDefault()});b(document).keydown(function(c){if(c.which===27){a.Chat.Modal.hide();c.preventDefault()}})},hideCloseControl:function(){b("#admin-message-cancel").hide().click(function(){})},showLoginForm:function(d,c){Candy.View.Pane.Chat.Modal.show((d?d:"")+Mustache.to_html(Candy.View.Template.Login.form,{_labelUsername:b.i18n._("labelUsername"),_labelPassword:b.i18n._("labelPassword"),_loginSubmit:b.i18n._("loginSubmit"),presetJid:(c?c:false)}));b("#login-form").submit(function(g){var h=b("#username").val(),e=b("#password").val(),f=Candy.Core.getUser()&&h.indexOf("@")<0?h+"@"+Strophe.getDomainFromJid(Candy.Core.getUser().getJid()):h;if(f.indexOf("@")<0&&!Candy.Core.getUser()){Candy.View.Pane.Chat.Modal.showLoginForm(b.i18n._("loginInvalid"))}else{Candy.Core.connect(f,e)}return false})}},Tooltip:{show:function(g,f){var h=b("#tooltip"),i=b(g.currentTarget);if(!f){f=i.attr("data-tooltip")}if(h.length===0){var d=Mustache.to_html(Candy.View.Template.Chat.tooltip);b("#chat-pane").append(d);h=b("#tooltip")}b("#context-menu").hide();h.stop(false,true);h.children("div").html(f);var j=i.offset(),c=Candy.Util.getPosLeftAccordingToWindowBounds(h,j.left),e=Candy.Util.getPosTopAccordingToWindowBounds(h,j.top);h.css({left:c.px,top:e.px,backgroundPosition:c.backgroundPositionAlignment+" "+e.backgroundPositionAlignment}).fadeIn("fast");i.mouseleave(function(k){k.stopPropagation();b("#tooltip").stop(false,true).fadeOut("fast",function(){b(this).css({top:0,left:0})})})}},Context:{init:function(){if(b("#context-menu").length===0){var c=Mustache.to_html(Candy.View.Template.Chat.Context.menu);b("#chat-pane").append(c);b("#context-menu").mouseleave(function(){b(this).fadeOut("fast")})}},show:function(e,p,h){e=b(e);var f=a.Chat.rooms[p].id,d=b("#context-menu"),o=b("ul li",d);b("#tooltip").hide();if(!h){h=Candy.Core.getUser()}o.remove();var k=this.getMenuLinks(p,h,e),c,l=function(r,q){return function(s){s.data.callback(s,r,q);b("#context-menu").hide()}};for(c in k){if(k.hasOwnProperty(c)){var n=k[c],j=Mustache.to_html(Candy.View.Template.Chat.Context.menulinks,{roomId:f,"class":n["class"],id:c,label:n.label});b("ul",d).append(j);b("#context-menu-"+c).bind("click",n,l(p,h))}}if(c){var m=e.offset(),g=Candy.Util.getPosLeftAccordingToWindowBounds(d,m.left),i=Candy.Util.getPosTopAccordingToWindowBounds(d,m.top);d.css({left:g.px,top:i.px,backgroundPosition:g.backgroundPositionAlignment+" "+i.backgroundPositionAlignment});d.fadeIn("fast");Candy.View.Event.Roster.afterContextMenu({roomJid:p,user:h,element:d});return true}},getMenuLinks:function(d,c,e){var f=b.extend(this.initialMenuLinks(e),Candy.View.Event.Roster.onContextMenu({roomJid:d,user:c,elem:e})),g;for(g in f){if(f.hasOwnProperty(g)&&f[g].requiredPermission!==undefined&&!f[g].requiredPermission(c,a.Room.getUser(d),e)){delete f[g]}}return f},initialMenuLinks:function(){return{"private":{requiredPermission:function(c,d){return d.getNick()!==c.getNick()&&Candy.Core.getRoom(Candy.View.getCurrent().roomJid)&&!Candy.Core.getUser().isInPrivacyList("ignore",c.getJid())},"class":"private",label:b.i18n._("privateActionLabel"),callback:function(f,d,c){b("#user-"+Candy.Util.jidToId(d)+"-"+Candy.Util.jidToId(c.getJid())).click()}},ignore:{requiredPermission:function(c,d){return d.getNick()!==c.getNick()&&!Candy.Core.getUser().isInPrivacyList("ignore",c.getJid())},"class":"ignore",label:b.i18n._("ignoreActionLabel"),callback:function(f,d,c){Candy.View.Pane.Room.ignoreUser(d,c.getJid())}},unignore:{requiredPermission:function(c,d){return d.getNick()!==c.getNick()&&Candy.Core.getUser().isInPrivacyList("ignore",c.getJid())},"class":"unignore",label:b.i18n._("unignoreActionLabel"),callback:function(f,d,c){Candy.View.Pane.Room.unignoreUser(d,c.getJid())}},kick:{requiredPermission:function(c,d){return d.getNick()!==c.getNick()&&d.isModerator()&&!c.isModerator()},"class":"kick",label:b.i18n._("kickActionLabel"),callback:function(f,d,c){a.Chat.Modal.show(Mustache.to_html(Candy.View.Template.Chat.Context.contextModalForm,{_label:b.i18n._("reason"),_submit:b.i18n._("kickActionLabel")}),true);b("#context-modal-field").focus();b("#context-modal-form").submit(function(e){Candy.Core.Action.Jabber.Room.Admin.UserAction(d,c.getJid(),"kick",b("#context-modal-field").val());a.Chat.Modal.hide();return false})}},ban:{requiredPermission:function(c,d){return d.getNick()!==c.getNick()&&d.isModerator()&&!c.isModerator()},"class":"ban",label:b.i18n._("banActionLabel"),callback:function(f,d,c){a.Chat.Modal.show(Mustache.to_html(Candy.View.Template.Chat.Context.contextModalForm,{_label:b.i18n._("reason"),_submit:b.i18n._("banActionLabel")}),true);b("#context-modal-field").focus();b("#context-modal-form").submit(function(g){Candy.Core.Action.Jabber.Room.Admin.UserAction(d,c.getJid(),"ban",b("#context-modal-field").val());a.Chat.Modal.hide();return false})}},subject:{requiredPermission:function(c,d){return d.getNick()===c.getNick()&&d.isModerator()},"class":"subject",label:b.i18n._("setSubjectActionLabel"),callback:function(f,d,c){a.Chat.Modal.show(Mustache.to_html(Candy.View.Template.Chat.Context.contextModalForm,{_label:b.i18n._("subject"),_submit:b.i18n._("setSubjectActionLabel")}),true);b("#context-modal-field").focus();b("#context-modal-form").submit(function(g){Candy.Core.Action.Jabber.Room.Admin.SetSubject(d,b("#context-modal-field").val());a.Chat.Modal.hide();g.preventDefault()})}}}},showEmoticonsMenu:function(h){h=b(h);var k=h.offset(),j=b("#context-menu"),g=b("ul",j),e="",d;b("#tooltip").hide();for(d=Candy.Util.Parser.emoticons.length-1;d>=0;d--){e='<img src="'+Candy.Util.Parser._emoticonPath+Candy.Util.Parser.emoticons[d].image+'" alt="'+Candy.Util.Parser.emoticons[d].plain+'" />'+e}g.html('<li class="emoticons">'+e+"</li>");g.find("img").click(function(){var i=Candy.View.Pane.Room.getPane(Candy.View.getCurrent().roomJid,".message-form").children(".field"),m=i.val(),l=b(this).attr("alt")+" ";i.val(m?m+" "+l:l).focus()});var c=Candy.Util.getPosLeftAccordingToWindowBounds(j,k.left),f=Candy.Util.getPosTopAccordingToWindowBounds(j,k.top);j.css({left:c.px,top:f.px,backgroundPosition:c.backgroundPositionAlignment+" "+f.backgroundPositionAlignment});j.fadeIn("fast");return true}}};a.Room={init:function(d,c,e){e=e||"groupchat";if(Candy.Util.isEmptyObject(a.Chat.rooms)){a.Chat.Toolbar.show()}var f=Candy.Util.jidToId(d);a.Chat.rooms[d]={id:f,usercount:0,name:c,type:e,messageCount:0,scrollPosition:-1};b("#chat-rooms").append(Mustache.to_html(Candy.View.Template.Room.pane,{roomId:f,roomJid:d,roomType:e,form:{_messageSubmit:b.i18n._("messageSubmit"),_maxLength:Candy.View.getOptions().crop.message.body},roster:{_userOnline:b.i18n._("userOnline")}},{roster:Candy.View.Template.Roster.pane,messages:Candy.View.Template.Message.pane,form:Candy.View.Template.Room.form}));a.Chat.addTab(d,c,e);a.Room.getPane(d,".message-form").submit(a.Message.submit);Candy.View.Event.Room.onAdd({roomJid:d,type:e,element:a.Room.getPane(d)});return f},show:function(c){var d=a.Chat.rooms[c].id;b(".room-pane").each(function(){var e=b(this);if(e.attr("id")===("chat-room-"+d)){e.show();Candy.View.getCurrent().roomJid=c;a.Chat.updateToolbar(c);a.Chat.setActiveTab(c);a.Chat.clearUnreadMessages(c);a.Room.setFocusToForm(c);a.Room.scrollToBottom(c);Candy.View.Event.Room.onShow({roomJid:c,element:e})}else{e.hide();Candy.View.Event.Room.onHide({roomJid:c,element:e})}})},setSubject:function(c,e){var d=Mustache.to_html(Candy.View.Template.Room.subject,{subject:e,roomName:a.Chat.rooms[c].name,_roomSubject:b.i18n._("roomSubject"),time:Candy.Util.localizedTime(new Date().toGMTString())});a.Room.appendToMessagePane(c,d);a.Room.scrollToBottom(c);Candy.View.Event.Room.onSubjectChange({roomJid:c,element:a.Room.getPane(c),subject:e})},close:function(c){a.Chat.removeTab(c);a.Window.clearUnreadMessages();a.Room.getPane(c).remove();var d=b("#chat-rooms").children();if(Candy.View.getCurrent().roomJid===c){Candy.View.getCurrent().roomJid=null;if(d.length===0){a.Chat.allTabsClosed()}else{a.Room.show(d.last().attr("data-roomjid"))}}delete a.Chat.rooms[c];Candy.View.Event.Room.onClose({roomJid:c})},appendToMessagePane:function(c,d){a.Room.getPane(c,".message-pane").append(d);a.Chat.rooms[c].messageCount++;a.Room.sliceMessagePane(c)},sliceMessagePane:function(c){if(a.Window.autoscroll){var d=Candy.View.getOptions().messages;if(a.Chat.rooms[c].messageCount>d.limit){a.Room.getPane(c,".message-pane").children().slice(0,d.remove*2).remove();a.Chat.rooms[c].messageCount-=d.remove}}},scrollToBottom:function(c){a.Room.onScrollToBottom(c)},onScrollToBottom:function(c){var d=a.Room.getPane(c,".message-pane-wrapper");d.scrollTop(d.prop("scrollHeight"))},onScrollToStoredPosition:function(c){if(a.Chat.rooms[c].scrollPosition>-1){var d=a.Room.getPane(c,".message-pane-wrapper");d.scrollTop(a.Chat.rooms[c].scrollPosition);a.Chat.rooms[c].scrollPosition=-1}},setFocusToForm:function(c){var f=a.Room.getPane(c,".message-form");if(f){try{f.children(".field")[0].focus()}catch(d){}}},setUser:function(d,c){a.Chat.rooms[d].user=c;var f=a.Room.getPane(d),e=b("#chat-pane");f.attr("data-userjid",c.getJid());if(c.isModerator()){if(c.getRole()===c.ROLE_MODERATOR){e.addClass("role-moderator")}if(c.getAffiliation()===c.AFFILIATION_OWNER){e.addClass("affiliation-owner")}}else{e.removeClass("role-moderator affiliation-owner")}a.Chat.Context.init()},getUser:function(c){return a.Chat.rooms[c].user},ignoreUser:function(c,d){Candy.Core.Action.Jabber.Room.IgnoreUnignore(d);Candy.View.Pane.Room.addIgnoreIcon(c,d)},unignoreUser:function(c,d){Candy.Core.Action.Jabber.Room.IgnoreUnignore(d);Candy.View.Pane.Room.removeIgnoreIcon(c,d)},addIgnoreIcon:function(c,d){if(Candy.View.Pane.Chat.rooms[d]){b("#user-"+Candy.View.Pane.Chat.rooms[d].id+"-"+Candy.Util.jidToId(d)).addClass("status-ignored")}if(Candy.View.Pane.Chat.rooms[Strophe.getBareJidFromJid(c)]){b("#user-"+Candy.View.Pane.Chat.rooms[Strophe.getBareJidFromJid(c)].id+"-"+Candy.Util.jidToId(d)).addClass("status-ignored")}},removeIgnoreIcon:function(c,d){if(Candy.View.Pane.Chat.rooms[d]){b("#user-"+Candy.View.Pane.Chat.rooms[d].id+"-"+Candy.Util.jidToId(d)).removeClass("status-ignored")}if(Candy.View.Pane.Chat.rooms[Strophe.getBareJidFromJid(c)]){b("#user-"+Candy.View.Pane.Chat.rooms[Strophe.getBareJidFromJid(c)].id+"-"+Candy.Util.jidToId(d)).removeClass("status-ignored")}},getPane:function(c,d){if(a.Chat.rooms[c]){if(d){if(a.Chat.rooms[c]["pane-"+d]){return a.Chat.rooms[c]["pane-"+d]}else{a.Chat.rooms[c]["pane-"+d]=b("#chat-room-"+a.Chat.rooms[c].id).find(d);return a.Chat.rooms[c]["pane-"+d]}}else{return b("#chat-room-"+a.Chat.rooms[c].id)}}}};a.PrivateRoom={open:function(e,c,f,g){var d=g?Candy.Core.getUser():a.Room.getUser(Strophe.getBareJidFromJid(e));if(Candy.Core.getUser().isInPrivacyList("ignore",e)){return false}if(!a.Chat.rooms[e]){a.Room.init(e,c,"chat")}if(f){a.Room.show(e)}a.Roster.update(e,new Candy.Core.ChatUser(e,c),"join",d);a.Roster.update(e,d,"join",d);a.PrivateRoom.setStatus(e,"join");if(g){a.Chat.infoMessage(e,b.i18n._("presenceUnknownWarningSubject"),b.i18n._("presenceUnknownWarning"))}Candy.View.Event.Room.onAdd({roomJid:e,type:"chat",element:a.Room.getPane(e)})},setStatus:function(d,c){var e=a.Room.getPane(d,".message-form");if(c==="join"){a.Chat.getTab(d).addClass("online").removeClass("offline");e.children(".field").removeAttr("disabled");e.children(".submit").removeAttr("disabled");a.Chat.getTab(d)}else{a.Chat.getTab(d).addClass("offline").removeClass("online");e.children(".field").attr("disabled",true);e.children(".submit").attr("disabled",true)}}};a.Roster={update:function(n,i,h,e){var f=a.Chat.rooms[n].id,k=Candy.Util.jidToId(i.getJid()),c=-1;if(h==="join"){c=1;var j=Mustache.to_html(Candy.View.Template.Roster.user,{roomId:f,userId:k,userJid:i.getJid(),nick:i.getNick(),displayNick:Candy.Util.crop(i.getNick(),Candy.View.getOptions().crop.roster.nickname),role:i.getRole(),affiliation:i.getAffiliation(),me:e!==undefined&&i.getNick()===e.getNick(),tooltipRole:b.i18n._("tooltipRole"),tooltipIgnored:b.i18n._("tooltipIgnored")}),m=b("#user-"+f+"-"+k);if(m.length<1){var d=false,l=a.Room.getPane(n,".roster-pane");if(l.children().length>0){var g=i.getNick().toUpperCase();l.children().each(function(){var o=b(this);if(o.attr("data-nick").toUpperCase()>g){o.before(j);d=true;return false}return true})}if(!d){l.append(j)}a.Roster.joinAnimation("user-"+f+"-"+k);if(e!==undefined&&i.getNick()!==e.getNick()&&a.Room.getUser(n)){if(a.Chat.rooms[n].type==="chat"){a.Chat.onInfoMessage(n,b.i18n._("userJoinedRoom",[i.getNick()]))}else{a.Chat.infoMessage(n,b.i18n._("userJoinedRoom",[i.getNick()]))}}}else{m.replaceWith(j);b("#user-"+f+"-"+k).css({opacity:1}).show()}if(e!==undefined&&e.getNick()===i.getNick()){a.Room.setUser(n,i)}else{b("#user-"+f+"-"+k).click(a.Roster.userClick)}b("#user-"+f+"-"+k+" .context").click(function(o){a.Chat.Context.show(o.currentTarget,n,i);o.stopPropagation()});if(e!==undefined&&e.isInPrivacyList("ignore",i.getJid())){Candy.View.Pane.Room.addIgnoreIcon(n,i.getJid())}}else{if(h==="leave"){a.Roster.leaveAnimation("user-"+f+"-"+k);if(a.Chat.rooms[n].type==="chat"){a.Chat.onInfoMessage(n,b.i18n._("userLeftRoom",[i.getNick()]))}else{a.Chat.infoMessage(n,b.i18n._("userLeftRoom",[i.getNick()]))}}else{if(h==="kick"){a.Roster.leaveAnimation("user-"+f+"-"+k);a.Chat.onInfoMessage(n,b.i18n._("userHasBeenKickedFromRoom",[i.getNick()]))}else{if(h==="ban"){a.Roster.leaveAnimation("user-"+f+"-"+k);a.Chat.onInfoMessage(n,b.i18n._("userHasBeenBannedFromRoom",[i.getNick()]))}}}}Candy.View.Pane.Chat.rooms[n].usercount+=c;if(n===Candy.View.getCurrent().roomJid){Candy.View.Pane.Chat.Toolbar.updateUsercount(Candy.View.Pane.Chat.rooms[n].usercount)}Candy.View.Event.Roster.onUpdate({roomJid:n,user:i,action:h,element:b("#user-"+f+"-"+k)})},userClick:function(){var c=b(this);a.PrivateRoom.open(c.attr("data-jid"),c.attr("data-nick"),true)},joinAnimation:function(c){b("#"+c).stop(true).slideDown("normal",function(){b(this).animate({opacity:1})})},leaveAnimation:function(c){b("#"+c).stop(true).attr("id","#"+c+"-leaving").animate({opacity:0},{complete:function(){b(this).slideUp("normal",function(){b(this).remove()})}})}};a.Message={submit:function(e){var c=Candy.View.Pane.Chat.rooms[Candy.View.getCurrent().roomJid].type,d=b(this).children(".field").val().substring(0,Candy.View.getOptions().crop.message.body);d=Candy.View.Event.Message.beforeSend(d);Candy.Core.Action.Jabber.Room.Message(Candy.View.getCurrent().roomJid,d,c);if(c==="chat"&&d){a.Message.show(Candy.View.getCurrent().roomJid,a.Room.getUser(Candy.View.getCurrent().roomJid).getNick(),d)}b(this).children(".field").val("").focus();e.preventDefault()},show:function(c,d,g,h){g=Candy.Util.Parser.all(g.substring(0,Candy.View.getOptions().crop.message.body));g=Candy.View.Event.Message.beforeShow(g);var e=Mustache.to_html(Candy.View.Template.Message.item,{name:d,displayName:Candy.Util.crop(d,Candy.View.getOptions().crop.message.nickname),message:g,time:Candy.Util.localizedTime(h||new Date().toGMTString())});a.Room.appendToMessagePane(c,e);var f=a.Room.getPane(c,".message-pane").children().last();f.find("a.name").click(function(i){i.preventDefault();if(d!==a.Room.getUser(Candy.View.getCurrent().roomJid).getNick()&&Candy.Core.getRoom(c).getRoster().get(c+"/"+d)){Candy.View.Pane.PrivateRoom.open(c+"/"+d,d,true)}});if(Candy.View.getCurrent().roomJid!==c||!a.Window.hasFocus()){a.Chat.increaseUnreadMessages(c);if(Candy.View.Pane.Chat.rooms[c].type==="chat"&&!a.Window.hasFocus()){a.Chat.Toolbar.playSound()}}if(Candy.View.getCurrent().roomJid===c){a.Room.scrollToBottom(c)}Candy.View.Event.Message.onShow({roomJid:c,element:f,nick:d,message:g})}};return a}(Candy.View.Pane||{},jQuery));Candy.View.Template=(function(a){a.Window={unreadmessages:"({{count}}) {{title}}"};a.Chat={pane:'<div id="chat-pane">{{> tabs}}{{> toolbar}}{{> rooms}}</div>{{> modal}}',rooms:'<div id="chat-rooms" class="rooms"></div>',tabs:'<ul id="chat-tabs"></ul>',tab:'<li class="roomtype-{{roomType}}" data-roomjid="{{roomJid}}" data-roomtype="{{roomType}}"><a href="#" class="label">{{#privateUserChat}}@{{/privateUserChat}}{{name}}</a><a href="#" class="transition"></a><a href="#" class="close">\u00D7</a><small class="unread"></small></li>',modal:'<div id="chat-modal"><a id="admin-message-cancel" class="close" href="#">\u00D7</a><span id="chat-modal-body"></span><img src="{{resourcesPath}}img/modal-spinner.gif" id="chat-modal-spinner" /></div><div id="chat-modal-overlay"></div>',adminMessage:'<dt>{{time}}</dt><dd class="adminmessage"><span class="label">{{sender}}</span>{{subject}} {{message}}</dd>',infoMessage:'<dt>{{time}}</dt><dd class="infomessage">{{subject}} {{message}}</dd>',toolbar:'<ul id="chat-toolbar"><li id="emoticons-icon" data-tooltip="{{tooltipEmoticons}}"></li><li id="chat-sound-control" class="checked" data-tooltip="{{tooltipSound}}">{{> soundcontrol}}</li><li id="chat-autoscroll-control" class="checked" data-tooltip="{{tooltipAutoscroll}}"></li><li class="checked" id="chat-statusmessage-control" data-tooltip="{{tooltipStatusmessage}}"></li><li class="context" data-tooltip="{{tooltipAdministration}}"></li><li class="usercount" data-tooltip="{{tooltipUsercount}}"><span id="chat-usercount"></span></li></ul>',soundcontrol:'<script type="text/javascript">var audioplayerListener = new Object(); audioplayerListener.onInit = function() { };<\/script><object id="chat-sound-player" type="application/x-shockwave-flash" data="{{resourcesPath}}audioplayer.swf" width="0" height="0"><param name="movie" value="{{resourcesPath}}audioplayer.swf" /><param name="AllowScriptAccess" value="always" /><param name="FlashVars" value="listener=audioplayerListener&amp;mp3={{resourcesPath}}notify.mp3" /></object>',Context:{menu:'<div id="context-menu"><ul></ul></div>',menulinks:'<li class="{{class}}" id="context-menu-{{id}}">{{label}}</li>',contextModalForm:'<form action="#" id="context-modal-form"><label for="context-modal-label">{{_label}}</label><input type="text" name="contextModalField" id="context-modal-field" /><input type="submit" class="button" name="send" value="{{_submit}}" /></form>',adminMessageReason:'<a id="admin-message-cancel" class="close" href="#">×</a><p>{{_action}}</p>{{#reason}}<p>{{_reason}}</p>{{/reason}}'},tooltip:'<div id="tooltip"><div></div></div>'};a.Room={pane:'<div class="room-pane roomtype-{{roomType}}" id="chat-room-{{roomId}}" data-roomjid="{{roomJid}}" data-roomtype="{{roomType}}">{{> roster}}{{> messages}}{{> form}}</div>',subject:'<dt>{{time}}</dt><dd class="subject"><span class="label">{{roomName}}</span>{{_roomSubject}} {{subject}}</dd>',form:'<div class="message-form-wrapper"></div><form method="post" class="message-form"><input name="message" class="field" type="text" autocomplete="off" maxlength="{{_maxLength}}" /><input type="submit" class="submit" name="submit" value="{{_messageSubmit}}" /></form>'};a.Roster={pane:'<div class="roster-pane"></div>',user:'<div class="user role-{{role}} affiliation-{{affiliation}}{{#me}} me{{/me}}" id="user-{{roomId}}-{{userId}}" data-jid="{{userJid}}" data-nick="{{nick}}" data-role="{{role}}" data-affiliation="{{affiliation}}"><div class="label">{{displayNick}}</div><ul><li class="context" id="context-{{roomId}}-{{userId}}"></li><li class="role role-{{role}} affiliation-{{affiliation}}" data-tooltip="{{tooltipRole}}"></li><li class="ignore" data-tooltip="{{tooltipIgnored}}"></li></ul></div>'};a.Message={pane:'<div class="message-pane-wrapper"><dl class="message-pane"></dl></div>',item:'<dt>{{time}}</dt><dd><span class="label"><a href="#" class="name">{{displayName}}</a></span>{{{message}}}</dd>'};a.Login={form:'<form method="post" id="login-form" class="login-form">{{^presetJid}}<label for="username">{{_labelUsername}}</label><input type="text" id="username" name="username"/>{{/presetJid}}{{#presetJid}}<input type="hidden" id="username" name="username" value="{{presetJid}}"/>{{/presetJid}}<label for="password">{{_labelPassword}}</label><input type="password" id="password" name="password" /><input type="submit" class="button" value="{{_loginSubmit}}" /></form>'};return a}(Candy.View.Template||{}));Candy.View.Translation={en:{status:"Status: %s",statusConnecting:"Connecting...",statusConnected:"Connected",statusDisconnecting:"Disconnecting...",statusDisconnected:"Disconnected",statusAuthfail:"Authentication failed",roomSubject:"Subject:",messageSubmit:"Send",labelUsername:"Username:",labelPassword:"Password:",loginSubmit:"Login",loginInvalid:"Invalid JID",reason:"Reason:",subject:"Subject:",reasonWas:"Reason was: %s.",kickActionLabel:"Kick",youHaveBeenKickedBy:"You have been kicked from %s by %s",banActionLabel:"Ban",youHaveBeenBannedBy:"You have been banned from %s by %s",privateActionLabel:"Private chat",ignoreActionLabel:"Ignore",unignoreActionLabel:"Unignore",setSubjectActionLabel:"Change Subject",administratorMessageSubject:"Administrator",userJoinedRoom:"%s joined the room.",userLeftRoom:"%s left the room.",userHasBeenKickedFromRoom:"%s has been kicked from the room.",userHasBeenBannedFromRoom:"%s has been banned from the room.",presenceUnknownWarningSubject:"Notice:",presenceUnknownWarning:"This user might be offline. We can't track his presence.",dateFormat:"dd.mm.yyyy",timeFormat:"HH:MM:ss",tooltipRole:"Moderator",tooltipIgnored:"You ignore this user",tooltipEmoticons:"Emoticons",tooltipSound:"Play sound for new private messages",tooltipAutoscroll:"Autoscroll",tooltipStatusmessage:"Display status messages",tooltipAdministration:"Room Administration",tooltipUsercount:"Room Occupants",raptorMessageBlocked:"Please do not spam. You have been blocked for a short-time."},de:{status:"Status: %s",statusConnecting:"Verbinden...",statusConnected:"Verbunden",statusDisconnecting:"Verbindung trennen...",statusDisconnected:"Verbindung getrennt",statusAuthfail:"Authentifizierung fehlgeschlagen",roomSubject:"Thema:",messageSubmit:"Senden",labelUsername:"Benutzername:",labelPassword:"Passwort:",loginSubmit:"Anmelden",loginInvalid:"Ungültige JID",reason:"Begründung:",subject:"Titel:",reasonWas:"Begründung: %s.",kickActionLabel:"Kick",youHaveBeenKickedBy:"Du wurdest soeben aus dem Raum %s gekickt (%s)",banActionLabel:"Ban",youHaveBeenBannedBy:"Du wurdest soeben aus dem Raum %s verbannt (%s)",privateActionLabel:"Privater Chat",ignoreActionLabel:"Ignorieren",unignoreActionLabel:"Nicht mehr ignorieren",setSubjectActionLabel:"Thema ändern",administratorMessageSubject:"Administrator",userJoinedRoom:"%s hat soeben den Raum betreten.",userLeftRoom:"%s hat soeben den Raum verlassen.",userHasBeenKickedFromRoom:"%s ist aus dem Raum gekickt worden.",userHasBeenBannedFromRoom:"%s ist aus dem Raum verbannt worden.",presenceUnknownWarningSubject:"Hinweis:",presenceUnknownWarning:"Dieser Benutzer könnte bereits abgemeldet sein. Wir können seine Anwesenheit nicht verfolgen.",dateFormat:"dd.mm.yyyy",timeFormat:"HH:MM:ss",tooltipRole:"Moderator",tooltipIgnored:"Du ignorierst diesen Benutzer",tooltipEmoticons:"Smileys",tooltipSound:"Ton abspielen bei neuen privaten Nachrichten",tooltipAutoscroll:"Autoscroll",tooltipStatusmessage:"Statusnachrichten anzeigen",tooltipAdministration:"Raum Administration",tooltipUsercount:"Anzahl Benutzer im Raum",raptorMessageBlocked:"Bitte nicht spammen. Du wurdest für eine kurze Zeit blockiert."},fr:{status:"Status: %s",statusConnecting:"Connecter...",statusConnected:"Connecté.",statusDisconnecting:"Déconnecter....",statusDisconnected:"Déconnecté.",statusAuthfail:"Authentification a échoué",roomSubject:"Sujet:",messageSubmit:"Envoyer",labelUsername:"Nom d'utilisateur:",labelPassword:"Mot de passe:",loginSubmit:"Inscription",loginInvalid:"JID invalide",reason:"Justification:",subject:"Titre:",reasonWas:"Justification: %s.",kickActionLabel:"Kick",youHaveBeenKickedBy:"Tu as été expulsé (%s)",banActionLabel:"Ban",youHaveBeenBannedBy:"Tu as été banni (%s)",privateActionLabel:"Chat privé",ignoreActionLabel:"Ignorer",unignoreActionLabel:"Ne plus ignorer",setSubjectActionLabel:"Changer le sujet",administratorMessageSubject:"Administrateur",userJoinedRoom:"%s vient d'entrer dans le salon.",userLeftRoom:"%s vient de quitter le salon.",userHasBeenKickedFromRoom:"%s a été expulsé du salon.",userHasBeenBannedFromRoom:"%s a été banni du salon.",presenceUnknownWarningSubject:"Note:",presenceUnknownWarning:"Cet utilisateur n'est malheureusement plus connecté, le message ne sera pas envoyé.",dateFormat:"dd.mm.yyyy",timeFormat:"HH:MM:ss",tooltipRole:"Modérateur",tooltipIgnored:"Tu ignores cette personne",tooltipEmoticons:"Smileys",tooltipSound:"Jouer un son lorsque tu reçois de nouveaux messages privés",tooltipAutoscroll:"Auto-defilement",tooltipStatusmessage:"Messages d'état",tooltipAdministration:"Administrer le salon",tooltipUsercount:"Nombre d'utilisateurs dans le salon",raptorMessageBlocked:"S'il te plaît, pas de spam. Tu as été bloqué pendant une courte période.."},nl:{status:"Status: %s",statusConnecting:"Verbinding maken...",statusConnected:"Verbinding is gereed",statusDisconnecting:"Verbinding verbreken...",statusDisconnected:"Verbinding is verbroken",statusAuthfail:"Authenticatie is mislukt",roomSubject:"Onderwerp:",messageSubmit:"Verstuur",labelUsername:"Gebruikersnaam:",labelPassword:"Wachtwoord:",loginSubmit:"Inloggen",loginInvalid:"JID is onjuist",reason:"Reden:",subject:"Onderwerp:",reasonWas:"De reden was: %s.",kickActionLabel:"Verwijderen",youHaveBeenKickedBy:"Je bent verwijderd van %s door %s",banActionLabel:"Blokkeren",youHaveBeenBannedBy:"Je bent geblokkeerd van %s door %s",privateActionLabel:"Prive gesprek",ignoreActionLabel:"Negeren",unignoreActionLabel:"Niet negeren",setSubjectActionLabel:"Onderwerp wijzigen",administratorMessageSubject:"Beheerder",userJoinedRoom:"%s komt de chat binnen.",userLeftRoom:"%s heeft de chat verlaten.",userHasBeenKickedFromRoom:"%s is verwijderd.",userHasBeenBannedFromRoom:"%s is geblokkeerd.",presenceUnknownWarningSubject:"Mededeling:",presenceUnknownWarning:"Deze gebruiker is waarschijnlijk offline, we kunnen zijn/haar aanwezigheid niet vaststellen.",dateFormat:"dd.mm.yyyy",timeFormat:"HH:MM:ss",tooltipRole:"Moderator",tooltipIgnored:"Je negeert deze gebruiker",tooltipEmoticons:"Emotie-iconen",tooltipSound:"Speel een geluid af bij nieuwe privé berichten.",tooltipAutoscroll:"Automatisch scrollen",tooltipStatusmessage:"Statusberichten weergeven",tooltipAdministration:"Instellingen",tooltipUsercount:"Gebruikers",raptorMessageBlocked:"Het is niet toegestaan om veel berichten naar de server te versturen. Je bent voor een korte periode geblokkeerd."},es:{status:"Estado: %s",statusConnecting:"Conectando...",statusConnected:"Conectado",statusDisconnecting:"Desconectando...",statusDisconnected:"Desconectado",statusAuthfail:"Falló la autenticación",roomSubject:"Asunto:",messageSubmit:"Enviar",labelUsername:"Usuario:",labelPassword:"Clave:",loginSubmit:"Entrar",loginInvalid:"JID no válido",reason:"Razón:",subject:"Asunto:",reasonWas:"La razón fue: %s.",kickActionLabel:"Expulsar",youHaveBeenKickedBy:"Has sido expulsado de %s por %s",banActionLabel:"Prohibir",youHaveBeenBannedBy:"Has sido expulsado permanentemente de %s por %s",privateActionLabel:"Chat privado",ignoreActionLabel:"Ignorar",unignoreActionLabel:"No ignorar",setSubjectActionLabel:"Cambiar asunto",administratorMessageSubject:"Administrador",userJoinedRoom:"%s se ha unido a la sala.",userLeftRoom:"%s ha dejado la sala.",userHasBeenKickedFromRoom:"%s ha sido expulsado de la sala.",userHasBeenBannedFromRoom:"%s ha sido expulsado permanentemente de la sala.",presenceUnknownWarningSubject:"Atención:",presenceUnknownWarning:"Éste usuario podría estar desconectado..",dateFormat:"dd.mm.yyyy",timeFormat:"HH:MM:ss",tooltipRole:"Moderador",tooltipIgnored:"Ignoras a éste usuario",tooltipEmoticons:"Emoticonos",tooltipSound:"Reproducir un sonido para nuevos mensajes privados",tooltipAutoscroll:"Desplazamiento automático",tooltipStatusmessage:"Mostrar mensajes de estado",tooltipAdministration:"Administración de la sala",tooltipUsercount:"Usuarios en la sala",raptorMessageBlocked:"Por favor, no hagas spam. Has sido bloqueado temporalmente."}}; \ No newline at end of file
+var Candy=(function(a,b){a.about={name:"Candy",version:"1.0.4"};a.init=function(c,d){a.View.init(b("#candy"),d.view);a.Core.init(c,d.core)};return a}(Candy||{},jQuery));Candy.Core=(function(l,e,f){var d=null,j=null,a=null,g={},c=false,k={autojoin:true,debug:false},b=function(m,n){e.addNamespace(m,n)},h=function(){b("PRIVATE","jabber:iq:private");b("BOOKMARKS","storage:bookmarks");b("PRIVACY","jabber:iq:privacy");b("DELAY","jabber:x:delay")},i=function(){d.addHandler(l.Event.Jabber.Version,e.NS.VERSION,"iq");d.addHandler(l.Event.Jabber.Presence,null,"presence");d.addHandler(l.Event.Jabber.Message,null,"message");d.addHandler(l.Event.Jabber.Bookmarks,e.NS.PRIVATE,"iq");d.addHandler(l.Event.Jabber.Room.Disco,e.NS.DISCO_INFO,"iq");d.addHandler(l.Event.Jabber.PrivacyList,e.NS.PRIVACY,"iq","result");d.addHandler(l.Event.Jabber.PrivacyListError,e.NS.PRIVACY,"iq","error")};l.init=function(m,n){j=m;f.extend(true,k,n);if(k.debug){l.log=function(p){try{if(typeof window.console!==undefined&&typeof window.console.log!==undefined){console.log(p)}}catch(o){}};l.log("[Init] Debugging enabled")}h();d=new e.Connection(j);d.rawInput=l.rawInput.bind(l);d.rawOutput=l.rawOutput.bind(l);window.onbeforeunload=l.onWindowUnload;if(f.browser.mozilla){f(document).keydown(function(o){if(o.which===27){o.preventDefault()}})}};l.connect=function(o,n,m){d.reset();i();c=!c?o&&o.indexOf("@")<0:true;if(o&&n){d.connect(_getEscapedJidFromJid(o)+"/"+Candy.about.name,n,Candy.Core.Event.Strophe.Connect);a=new l.ChatUser(o,e.getNodeFromJid(o))}else{if(o&&m){d.connect(_getEscapedJidFromJid(o)+"/"+Candy.about.name,null,Candy.Core.Event.Strophe.Connect);a=new l.ChatUser(null,m)}else{if(o){Candy.Core.Event.Login(o)}else{Candy.Core.Event.Login()}}}};_getEscapedJidFromJid=function(m){var n=e.getNodeFromJid(m),o=e.getDomainFromJid(m);return n?e.escapeNode(n)+"@"+o:o};l.attach=function(n,m,o){a=new l.ChatUser(n,e.getNodeFromJid(n));i();d.attach(n,m,o,Candy.Core.Event.Strophe.Connect)};l.disconnect=function(){if(d.connected){f.each(l.getRooms(),function(){Candy.Core.Action.Jabber.Room.Leave(this.getJid())});d.disconnect()}};l.getUser=function(){return a};l.setUser=function(m){a=m};l.getConnection=function(){return d};l.getRooms=function(){return g};l.isAnonymousConnection=function(){return c};l.getOptions=function(){return k};l.getRoom=function(m){if(g[m]){return g[m]}return null};l.onWindowUnload=function(){d.sync=true;l.disconnect();d.flush()};l.rawInput=function(m){this.log("RECV: "+m)};l.rawOutput=function(m){this.log("SENT: "+m)};l.log=function(){};return l}(Candy.Core||{},Strophe,jQuery));Candy.View=(function(i,b){var d={container:null,roomJid:null},h={language:"en",resources:"res/",messages:{limit:2000,remove:500},crop:{message:{nickname:15,body:1000},roster:{nickname:15}}},a=function(j){b.i18n.setDictionary(i.Translation[j])},g=function(){Candy.Core.Event.addObserver(Candy.Core.Event.KEYS.CHAT,i.Observer.Chat);Candy.Core.Event.addObserver(Candy.Core.Event.KEYS.PRESENCE,i.Observer.Presence);Candy.Core.Event.addObserver(Candy.Core.Event.KEYS.MESSAGE,i.Observer.Message);Candy.Core.Event.addObserver(Candy.Core.Event.KEYS.LOGIN,i.Observer.Login)},e=function(){if(b.browser.msie&&!b.browser.version.match("^9")){b(document).focusin(Candy.View.Pane.Window.onFocus).focusout(Candy.View.Pane.Window.onBlur)}else{b(window).focus(Candy.View.Pane.Window.onFocus).blur(Candy.View.Pane.Window.onBlur)}b(window).resize(Candy.View.Pane.Chat.fitTabs)},f=function(){b("#emoticons-icon").click(function(j){i.Pane.Chat.Context.showEmoticonsMenu(j.currentTarget);j.stopPropagation()});b("#chat-autoscroll-control").click(Candy.View.Pane.Chat.Toolbar.onAutoscrollControlClick);b("#chat-sound-control").click(Candy.View.Pane.Chat.Toolbar.onSoundControlClick);if(Candy.Util.cookieExists("candy-nosound")){b("#chat-sound-control").click()}b("#chat-statusmessage-control").click(Candy.View.Pane.Chat.Toolbar.onStatusMessageControlClick);if(Candy.Util.cookieExists("candy-nostatusmessages")){b("#chat-statusmessage-control").click()}},c=function(){b("body").delegate("li[data-tooltip]","mouseenter",Candy.View.Pane.Chat.Tooltip.show)};i.init=function(j,k){b.extend(true,h,k);a(h.language);Candy.Util.Parser.setEmoticonPath(this.getOptions().resources+"img/emoticons/");d.container=j;d.container.html(Mustache.to_html(Candy.View.Template.Chat.pane,{tooltipEmoticons:b.i18n._("tooltipEmoticons"),tooltipSound:b.i18n._("tooltipSound"),tooltipAutoscroll:b.i18n._("tooltipAutoscroll"),tooltipStatusmessage:b.i18n._("tooltipStatusmessage"),tooltipAdministration:b.i18n._("tooltipAdministration"),tooltipUsercount:b.i18n._("tooltipUsercount"),resourcesPath:this.getOptions().resources},{tabs:Candy.View.Template.Chat.tabs,rooms:Candy.View.Template.Chat.rooms,modal:Candy.View.Template.Chat.modal,toolbar:Candy.View.Template.Chat.toolbar,soundcontrol:Candy.View.Template.Chat.soundcontrol}));e();f();g();c()};i.getCurrent=function(){return d};i.getOptions=function(){return h};return i}(Candy.View||{},jQuery));Candy.Util=(function(a,b){a.jidToId=function(c){return MD5.hexdigest(c)};a.escapeJid=function(c){var d=Strophe.escapeNode(Strophe.getNodeFromJid(c)),f=Strophe.getDomainFromJid(c),e=Strophe.getResourceFromJid(c);c=d+"@"+f;if(e){c+="/"+Strophe.escapeNode(e)}return c};a.unescapeJid=function(c){var d=Strophe.unescapeNode(Strophe.getNodeFromJid(c)),f=Strophe.getDomainFromJid(c),e=Strophe.getResourceFromJid(c);c=d+"@"+f;if(e){c+="/"+Strophe.unescapeNode(e)}return c};a.crop=function(d,c){if(d.length>c){d=d.substr(0,c-3)+"..."}return d};a.setCookie=function(c,e,d){var f=new Date();f.setDate(new Date().getDate()+d);document.cookie=c+"="+e+";expires="+f.toUTCString()+";path=/"};a.cookieExists=function(c){return document.cookie.indexOf(c)>-1};a.getCookie=function(c){if(document.cookie){var d=new RegExp(escape(c)+"=([^;]*)","gm"),e=d.exec(document.cookie);if(e){return e[1]}}};a.deleteCookie=function(c){document.cookie=c+"=;expires=Thu, 01-Jan-70 00:00:01 GMT"};a.getPosLeftAccordingToWindowBounds=function(e,h){var d=b(document).width(),c=e.outerWidth(),f=c-e.outerWidth(true),g="left";if(h+c>=d){h-=c-f;g="right"}return{px:h,backgroundPositionAlignment:g}};a.getPosTopAccordingToWindowBounds=function(d,h){var g=b(document).height(),c=d.outerHeight(),e=c-d.outerHeight(true),f="top";if(h+c>=g){h-=c-e;f="bottom"}return{px:h,backgroundPositionAlignment:f}};a.localizedTime=function(d){if(d===undefined){return undefined}var c=a.iso8601toDate(d);if(c.toDateString()===new Date().toDateString()){return c.format(b.i18n._("timeFormat"))}else{return c.format(b.i18n._("dateFormat"))}};a.iso8601toDate=function(c){var e=Date.parse(c),d=0;if(isNaN(e)){var f=/^(\d{4}|[+\-]\d{6})-(\d{2})-(\d{2})(?:[T ](\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3,}))?)?(?:(Z)|([+\-])(\d{2})(?::?(\d{2}))?))?/.exec(c);if(f){if(f[8]!=="Z"){d=+f[10]*60+(+f[11]);if(f[9]==="+"){d=-d}}return new Date(+f[1],+f[2]-1,+f[3],+f[4],+f[5]+d,+f[6],f[7]?+f[7].substr(0,3):0)}else{e=Date.parse(c.replace(/^(\d{4})(\d{2})(\d{2})/,"$1-$2-$3")+"Z")}}return new Date(e)};a.isEmptyObject=function(c){var d;for(d in c){if(c.hasOwnProperty(d)){return false}}return true};a.forceRedraw=function(c){c.css({display:"none"});setTimeout(function(){this.css({display:"block"})}.bind(c),1)};a.Parser={_emoticonPath:"",setEmoticonPath:function(c){this._emoticonPath=c},emoticons:[{plain:":)",regex:/((\s):-?\)|:-?\)(\s|$))/gm,image:"Smiling.png"},{plain:";)",regex:/((\s);-?\)|;-?\)(\s|$))/gm,image:"Winking.png"},{plain:":D",regex:/((\s):-?D|:-?D(\s|$))/gm,image:"Grinning.png"},{plain:";D",regex:/((\s);-?D|;-?D(\s|$))/gm,image:"Grinning_Winking.png"},{plain:":(",regex:/((\s):-?\(|:-?\((\s|$))/gm,image:"Unhappy.png"},{plain:"^^",regex:/((\s)\^\^|\^\^(\s|$))/gm,image:"Happy_3.png"},{plain:":P",regex:/((\s):-?P|:-?P(\s|$))/igm,image:"Tongue_Out.png"},{plain:";P",regex:/((\s);-?P|;-?P(\s|$))/igm,image:"Tongue_Out_Winking.png"},{plain:":S",regex:/((\s):-?S|:-?S(\s|$))/igm,image:"Confused.png"},{plain:":/",regex:/((\s):-?\/|:-?\/(\s|$))/gm,image:"Uncertain.png"},{plain:"8)",regex:/((\s)8-?\)|8-?\)(\s|$))/gm,image:"Sunglasses.png"},{plain:"$)",regex:/((\s)\$-?\)|\$-?\)(\s|$))/gm,image:"Greedy.png"},{plain:"oO",regex:/((\s)oO|oO(\s|$))/gm,image:"Huh.png"},{plain:":x",regex:/((\s):x|:x(\s|$))/gm,image:"Lips_Sealed.png"},{plain:":666:",regex:/((\s):666:|:666:(\s|$))/gm,image:"Devil.png"},{plain:"<3",regex:/((\s)&lt;3|&lt;3(\s|$))/gm,image:"Heart.png"}],emotify:function(d){var c;for(c=this.emoticons.length-1;c>=0;c--){d=d.replace(this.emoticons[c].regex,'$2<img class="emoticon" alt="$1" src="'+this._emoticonPath+this.emoticons[c].image+'" />$3')}return d},linkify:function(c){c=c.replace(/(^|[^\/])(www\.[^\.]+\.[\S]+(\b|$))/gi,"$1http://$2");return c.replace(/(\b(https?|ftp|file):\/\/[\-A-Z0-9+&@#\/%?=~_|!:,.;]*[\-A-Z0-9+&@#\/%=~_|])/ig,'<a href="$1" target="_blank">$1</a>')},escape:function(c){return b("<div/>").text(c).html()},all:function(c){if(c){c=this.escape(c);c=this.linkify(c);c=this.emotify(c)}return c}};return a}(Candy.Util||{},jQuery));Candy.Util.Observable=(function(a){var b={};a.addObserver=function(c,d){if(b[c]===undefined){b[c]=[]}b[c].push(d)};a.deleteObserver=function(c,d){delete b[c][d]};a.clearObservers=function(c){if(c!==undefined){b[c]=[]}else{b={}}};a.notifyObservers=function(f,c){var d=b[f],e;for(e=d.length-1;e>=0;e--){d[e].update(a,c)}};return a}(Candy.Util.Observable||{}));Candy.Core.Action=(function(a,c,b){a.Jabber={Version:function(d){Candy.Core.getConnection().send($iq({type:"result",to:d.attr("from"),from:d.attr("to"),id:d.attr("id")}).c("query",{name:Candy.about.name,version:Candy.about.version,os:navigator.userAgent}))},Roster:function(){Candy.Core.getConnection().send($iq({type:"get",xmlns:c.NS.CLIENT}).c("query",{xmlns:c.NS.ROSTER}).tree())},Presence:function(d){Candy.Core.getConnection().send($pres(d).tree())},Services:function(){Candy.Core.getConnection().send($iq({type:"get",xmlns:c.NS.CLIENT}).c("query",{xmlns:c.NS.DISCO_ITEMS}).tree())},Autojoin:function(){if(Candy.Core.getOptions().autojoin===true){Candy.Core.getConnection().send($iq({type:"get",xmlns:c.NS.CLIENT}).c("query",{xmlns:c.NS.PRIVATE}).c("storage",{xmlns:c.NS.BOOKMARKS}).tree())}else{if(b.isArray(Candy.Core.getOptions().autojoin)){b.each(Candy.Core.getOptions().autojoin,function(){a.Jabber.Room.Join(this.valueOf())})}}},ResetIgnoreList:function(){Candy.Core.getConnection().send($iq({type:"set",from:Candy.Core.getUser().getJid(),id:"set1"}).c("query",{xmlns:c.NS.PRIVACY}).c("list",{name:"ignore"}).c("item",{action:"allow",order:"0"}).tree())},RemoveIgnoreList:function(){Candy.Core.getConnection().send($iq({type:"set",from:Candy.Core.getUser().getJid(),id:"remove1"}).c("query",{xmlns:c.NS.PRIVACY}).c("list",{name:"ignore"}).tree())},GetIgnoreList:function(){Candy.Core.getConnection().send($iq({type:"get",from:Candy.Core.getUser().getJid(),id:"get1"}).c("query",{xmlns:c.NS.PRIVACY}).c("list",{name:"ignore"}).tree())},SetIgnoreListActive:function(){Candy.Core.getConnection().send($iq({type:"set",from:Candy.Core.getUser().getJid(),id:"set2"}).c("query",{xmlns:c.NS.PRIVACY}).c("active",{name:"ignore"}).tree())},GetJidIfAnonymous:function(){if(!Candy.Core.getUser().getJid()){Candy.Core.log("[Jabber] Anonymous login");Candy.Core.getUser().data.jid=Candy.Core.getConnection().jid}},Room:{Join:function(d){a.Jabber.Room.Disco(d);Candy.Core.getConnection().muc.join(d,Candy.Core.getUser().getNick())},Leave:function(d){Candy.Core.getConnection().muc.leave(d,Candy.Core.getRoom(d).getUser().getNick(),function(){})},Disco:function(d){Candy.Core.getConnection().send($iq({type:"get",from:Candy.Core.getUser().getJid(),to:d,id:"disco3"}).c("query",{xmlns:c.NS.DISCO_INFO}).tree())},Message:function(d,f,e){f=b.trim(f);if(f===""){return false}Candy.Core.getConnection().muc.message(Candy.Util.escapeJid(d),undefined,f,e);return true},IgnoreUnignore:function(d){Candy.Core.getUser().addToOrRemoveFromPrivacyList("ignore",d);Candy.Core.Action.Jabber.Room.UpdatePrivacyList()},UpdatePrivacyList:function(){var d=Candy.Core.getUser(),f=$iq({type:"set",from:d.getJid(),id:"edit1"}).c("query",{xmlns:"jabber:iq:privacy"}).c("list",{name:"ignore"}),e=d.getPrivacyList("ignore");if(e.length>0){b.each(e,function(g,h){f.c("item",{type:"jid",value:Candy.Util.escapeJid(h),action:"deny",order:g}).c("message").up().up()})}else{f.c("item",{action:"allow",order:"0"})}Candy.Core.getConnection().send(f.tree())},Admin:{UserAction:function(d,i,g,h){var f,e={nick:c.escapeNode(c.getResourceFromJid(i))};switch(g){case"kick":f="kick1";e.role="none";break;case"ban":f="ban1";e.affiliation="outcast";break;default:return false}Candy.Core.getConnection().send($iq({type:"set",from:Candy.Core.getUser().getJid(),to:d,id:f}).c("query",{xmlns:c.NS.MUC_ADMIN}).c("item",e).c("reason").t(h).tree());return true},SetSubject:function(d,e){Candy.Core.getConnection().muc.setTopic(d,e)}}}};return a}(Candy.Core.Action||{},Strophe,jQuery));Candy.Core.ChatRoom=function(a){this.room={jid:a,name:null};this.user=null;this.roster=new Candy.Core.ChatRoster();this.setUser=function(b){this.user=b};this.getUser=function(){return this.user};this.getJid=function(){return this.room.jid};this.setName=function(b){this.room.name=b};this.getName=function(){return this.room.name};this.setRoster=function(b){this.roster=b};this.getRoster=function(){return this.roster}};Candy.Core.ChatRoster=function(){this.items={};this.add=function(a){this.items[a.getJid()]=a};this.remove=function(a){delete this.items[a]};this.get=function(a){return this.items[a]};this.getAll=function(){return this.items}};Candy.Core.ChatUser=function(b,a,c,d){this.ROLE_MODERATOR="moderator";this.AFFILIATION_OWNER="owner";this.data={jid:b,nick:Strophe.unescapeNode(a),affiliation:c,role:d,privacyLists:{},customData:{}};this.getJid=function(){return Candy.Util.unescapeJid(this.data.jid)};this.getEscapedJid=function(){return Candy.Util.escapeJid(this.data.jid)};this.getNick=function(){return Strophe.unescapeNode(this.data.nick)};this.getRole=function(){return this.data.role};this.getAffiliation=function(){return this.data.affiliation};this.isModerator=function(){return this.getRole()===this.ROLE_MODERATOR||this.getAffiliation()===this.AFFILIATION_OWNER};this.addToOrRemoveFromPrivacyList=function(g,f){if(!this.data.privacyLists[g]){this.data.privacyLists[g]=[]}var e=-1;if((e=this.data.privacyLists[g].indexOf(f))!==-1){this.data.privacyLists[g].splice(e,1)}else{this.data.privacyLists[g].push(f)}return this.data.privacyLists[g]};this.getPrivacyList=function(e){if(!this.data.privacyLists[e]){this.data.privacyLists[e]=[]}return this.data.privacyLists[e]};this.isInPrivacyList=function(f,e){if(!this.data.privacyLists[f]){return false}return this.data.privacyLists[f].indexOf(e)!==-1};this.setCustomData=function(e){this.data.customData=e};this.getCustomData=function(){return this.data.customData}};Candy.Core.Event=(function(a,e,c,d){var b;for(b in d){if(d.hasOwnProperty(b)){a[b]=d[b]}}a.KEYS={CHAT:1,PRESENCE:2,MESSAGE:3,LOGIN:4};a.Strophe={Connect:function(f){switch(f){case e.Status.CONNECTED:Candy.Core.log("[Connection] Connected");Candy.Core.Action.Jabber.GetJidIfAnonymous();case e.Status.ATTACHED:Candy.Core.log("[Connection] Attached");Candy.Core.Action.Jabber.Presence();Candy.Core.Action.Jabber.Autojoin();Candy.Core.Action.Jabber.GetIgnoreList();break;case e.Status.DISCONNECTED:Candy.Core.log("[Connection] Disconnected");break;case e.Status.AUTHFAIL:Candy.Core.log("[Connection] Authentication failed");break;case e.Status.CONNECTING:Candy.Core.log("[Connection] Connecting");break;case e.Status.DISCONNECTING:Candy.Core.log("[Connection] Disconnecting");break;case e.Status.AUTHENTICATING:Candy.Core.log("[Connection] Authenticating");break;case e.Status.ERROR:case e.Status.CONNFAIL:Candy.Core.log("[Connection] Failed ("+f+")");break;default:Candy.Core.log("[Connection] What?!");break}a.notifyObservers(a.KEYS.CHAT,{type:"connection",status:f})}};a.Login=function(f){a.notifyObservers(a.KEYS.LOGIN,{presetJid:f})};a.Jabber={Version:function(f){Candy.Core.log("[Jabber] Version");Candy.Core.Action.Jabber.Version(c(f));return true},Presence:function(f){Candy.Core.log("[Jabber] Presence");f=c(f);if(f.children('x[xmlns^="'+e.NS.MUC+'"]').length>0){a.Jabber.Room.Presence(f)}return true},Bookmarks:function(f){Candy.Core.log("[Jabber] Bookmarks");c("conference",f).each(function(){var g=c(this);if(g.attr("autojoin")){Candy.Core.Action.Jabber.Room.Join(g.attr("jid"))}});return true},PrivacyList:function(g){Candy.Core.log("[Jabber] PrivacyList");var f=Candy.Core.getUser();c('list[name="ignore"] item',g).each(function(){var h=c(this);if(h.attr("action")==="deny"){f.addToOrRemoveFromPrivacyList("ignore",h.attr("value"))}});Candy.Core.Action.Jabber.SetIgnoreListActive();return false},PrivacyListError:function(f){Candy.Core.log("[Jabber] PrivacyListError");if(c('error[code="404"][type="cancel"] item-not-found',f)){Candy.Core.Action.Jabber.ResetIgnoreList();Candy.Core.Action.Jabber.SetIgnoreListActive()}return false},Message:function(i){Candy.Core.log("[Jabber] Message");var i=c(i),h=i.attr("from"),g=i.attr("type"),f=i.attr("to");if(h!==e.getDomainFromJid(h)&&(g==="groupchat"||g==="chat"||g==="error")){a.Jabber.Room.Message(i)}else{if(!f&&h===e.getDomainFromJid(h)){a.notifyObservers(a.KEYS.CHAT,{type:(g||"message"),message:i.children("body").text()})}else{if(f&&h===e.getDomainFromJid(h)){a.notifyObservers(a.KEYS.CHAT,{type:(g||"message"),subject:i.children("subject").text(),message:i.children("body").text()})}}}return true},Room:{Leave:function(f){Candy.Core.log("[Jabber:Room] Leave");var f=c(f),l=f.attr("from"),n=e.getBareJidFromJid(l),j=Candy.Core.getRoom(n).getName(),m=f.find("item"),k="leave",i,h;delete Candy.Core.getRooms()[n];if(m.attr("role")==="none"){if(f.find("status").attr("code")==="307"){k="kick"}else{if(f.find("status").attr("code")==="301"){k="ban"}}i=m.find("reason").text();h=m.find("actor").attr("jid")}var g=new Candy.Core.ChatUser(l,e.getResourceFromJid(l),m.attr("affiliation"),m.attr("role"));a.notifyObservers(a.KEYS.PRESENCE,{roomJid:n,roomName:j,type:k,reason:i,actor:h,user:g});return true},Disco:function(i){Candy.Core.log("[Jabber:Room] Disco");var i=c(i),g=e.getBareJidFromJid(i.attr("from"));if(!Candy.Core.getRooms()[g]){Candy.Core.getRooms()[g]=new Candy.Core.ChatRoom(g)}var f=i.find("identity").attr("name"),h=Candy.Core.getRoom(g);if(h.getName()===null){h.setName(f)}return true},Presence:function(h){Candy.Core.log("[Jabber:Room] Presence");var l=Candy.Util.unescapeJid(h.attr("from")),o=e.getBareJidFromJid(l),m=h.attr("type");if(e.getResourceFromJid(l)===Candy.Core.getUser().getNick()&&m==="unavailable"){a.Jabber.Room.Leave(h);return true}if(m==="error"){Candy.Core.log("[Jabber:Room] Presence Error");delete Candy.Core.getRooms()[o];return true}var g=Candy.Core.getRoom(o);if(!g){Candy.Core.getRooms()[o]=new Candy.Core.ChatRoom(o);g=Candy.Core.getRoom(o)}var k=g.getRoster(),i,j,n=h.find("item");if(m!=="unavailable"){var f=e.getResourceFromJid(l);j=new Candy.Core.ChatUser(l,f,n.attr("affiliation"),n.attr("role"));if(g.getUser()===null&&Candy.Core.getUser().getNick()===f){g.setUser(j)}k.add(j);i="join"}else{i="leave";if(n.attr("role")==="none"){if(h.find("status").attr("code")==="307"){i="kick"}else{if(h.find("status").attr("code")==="301"){i="ban"}}}j=k.get(l);k.remove(l)}a.notifyObservers(a.KEYS.PRESENCE,{roomJid:o,roomName:g.getName(),user:j,action:i,currentUser:Candy.Core.getUser()});return true},Message:function(h){Candy.Core.log("[Jabber:Room] Message");var o,n;if(h.children("subject").length>0){o=Candy.Util.unescapeJid(e.getBareJidFromJid(h.attr("from")));n={name:e.getNodeFromJid(o),body:h.children("subject").text(),type:"subject"}}else{if(h.attr("type")==="error"){var m=h.children("error");if(m.attr("code")==="500"&&m.children("text").length>0){o=h.attr("from");n={type:"info",body:m.children("text").text()}}}else{if(h.children("body").length>0){if(h.attr("type")==="chat"){o=Candy.Util.unescapeJid(h.attr("from"));var f=e.getBareJidFromJid(o),i=!Candy.Core.getRoom(f),g=i?e.getNodeFromJid(o):e.getResourceFromJid(o);n={name:g,body:h.children("body").text(),type:h.attr("type"),isNoConferenceRoomJid:i}}else{o=Candy.Util.unescapeJid(e.getBareJidFromJid(h.attr("from")));var j=e.getResourceFromJid(h.attr("from"));if(j){j=e.unescapeNode(j);n={name:j,body:h.children("body").text(),type:h.attr("type")}}else{n={name:"",body:h.children("body").text(),type:"info"}}}}else{return true}}}var k=h.children("delay")?h.children("delay"):h.children('x[xmlns="'+e.NS.DELAY+'"]'),l=k!==undefined?k.attr("stamp"):null;a.notifyObservers(a.KEYS.MESSAGE,{roomJid:o,message:n,timestamp:l});return true}}};return a}(Candy.Core.Event||{},Strophe,jQuery,Candy.Util.Observable));Candy.View.Event=(function(a,b){a.Chat={onAdminMessage:function(c){return},onDisconnect:function(){return},onAuthfail:function(){return}};a.Room={onAdd:function(c){return},onShow:function(c){return},onHide:function(c){return},onSubjectChange:function(c){return},onClose:function(c){return},onPresenceChange:function(c){return}};a.Roster={onUpdate:function(c){return},onContextMenu:function(c){return{}},afterContextMenu:function(c){return}};a.Message={beforeShow:function(c){return c.message},onShow:function(c){return},beforeSend:function(c){return c}};return a}(Candy.View.Event||{},jQuery));Candy.View.Observer=(function(a,b){a.Chat={update:function(d,c){if(c.type==="connection"){switch(c.status){case Strophe.Status.CONNECTING:case Strophe.Status.AUTHENTICATING:Candy.View.Pane.Chat.Modal.show(b.i18n._("statusConnecting"),false,true);break;case Strophe.Status.ATTACHED:case Strophe.Status.CONNECTED:Candy.View.Pane.Chat.Modal.show(b.i18n._("statusConnected"));Candy.View.Pane.Chat.Modal.hide();break;case Strophe.Status.DISCONNECTING:Candy.View.Pane.Chat.Modal.show(b.i18n._("statusDisconnecting"),false,true);break;case Strophe.Status.DISCONNECTED:Candy.View.Pane.Chat.Modal.showLoginForm(b.i18n._("statusDisconnected"));Candy.View.Event.Chat.onDisconnect();break;case Strophe.Status.AUTHFAIL:Candy.View.Pane.Chat.Modal.showLoginForm(b.i18n._("statusAuthfail"));Candy.View.Event.Chat.onAuthfail();break;default:Candy.View.Pane.Chat.Modal.show(b.i18n._("status",c.status));break}}else{if(c.type==="message"){Candy.View.Pane.Chat.adminMessage((c.subject||""),c.message)}else{if(c.type==="chat"||c.type==="groupchat"){Candy.View.Pane.Chat.onInfoMessage(Candy.View.getCurrent().roomJid,(c.subject||""),c.message)}}}}};a.Presence={update:function(g,d){if(d.type==="leave"){var c=Candy.View.Pane.Room.getUser(d.roomJid);Candy.View.Pane.Room.close(d.roomJid);a.Presence.notifyPrivateChats(c,d.type)}else{if(d.type==="kick"||d.type==="ban"){var f=d.actor?Strophe.getNodeFromJid(d.actor):d.roomName,e;switch(d.type){case"kick":e=b.i18n._("youHaveBeenKickedBy",[d.roomName,f]);break;case"ban":e=b.i18n._("youHaveBeenBannedBy",[d.roomName,f]);break}Candy.View.Pane.Chat.Modal.show(Mustache.to_html(Candy.View.Template.Chat.Context.adminMessageReason,{reason:d.reason,_action:e,_reason:b.i18n._("reasonWas",[d.reason])}));setTimeout(function(){Candy.View.Pane.Chat.Modal.hide(function(){Candy.View.Pane.Room.close(d.roomJid);a.Presence.notifyPrivateChats(d.user,d.type)})},5000);Candy.View.Event.Room.onPresenceChange({type:d.type,reason:d.reason,roomJid:d.roomJid,user:d.user})}else{if(!Candy.View.Pane.Chat.rooms[d.roomJid]){Candy.View.Pane.Room.init(d.roomJid,d.roomName);Candy.View.Pane.Room.show(d.roomJid)}Candy.View.Pane.Roster.update(d.roomJid,d.user,d.action,d.currentUser);if(Candy.View.Pane.Chat.rooms[d.user.getJid()]){Candy.View.Pane.Roster.update(d.user.getJid(),d.user,d.action,d.currentUser);Candy.View.Pane.PrivateRoom.setStatus(d.user.getJid(),d.action)}}}},notifyPrivateChats:function(d,e){Candy.Core.log("[View:Observer] notify Private Chats");var c;for(c in Candy.View.Pane.Chat.rooms){if(Candy.View.Pane.Chat.rooms.hasOwnProperty(c)&&Candy.View.Pane.Room.getUser(c)&&d.getJid()===Candy.View.Pane.Room.getUser(c).getJid()){Candy.View.Pane.Roster.update(c,d,e,d);Candy.View.Pane.PrivateRoom.setStatus(c,e)}}}};a.Message={update:function(d,c){if(c.message.type==="subject"){if(!Candy.View.Pane.Chat.rooms[c.roomJid]){Candy.View.Pane.Room.init(c.roomJid,c.message.name);Candy.View.Pane.Room.show(c.roomJid)}Candy.View.Pane.Room.setSubject(c.roomJid,c.message.body)}else{if(c.message.type==="info"){Candy.View.Pane.Chat.infoMessage(c.roomJid,c.message.body)}else{if(c.message.type==="chat"&&!Candy.View.Pane.Chat.rooms[c.roomJid]){Candy.View.Pane.PrivateRoom.open(c.roomJid,c.message.name,false,c.message.isNoConferenceRoomJid)}Candy.View.Pane.Message.show(c.roomJid,c.message.name,c.message.body,c.timestamp)}}}};a.Login={update:function(d,c){Candy.View.Pane.Chat.Modal.showLoginForm(null,c.presetJid)}};return a}(Candy.View.Observer||{},jQuery));Candy.View.Pane=(function(a,b){a.Window={_hasFocus:true,_plainTitle:document.title,_unreadMessagesCount:0,autoscroll:true,hasFocus:function(){return a.Window._hasFocus},increaseUnreadMessages:function(){a.Window.renderUnreadMessages(++a.Window._unreadMessagesCount)},reduceUnreadMessages:function(c){a.Window._unreadMessagesCount-=c;if(a.Window._unreadMessagesCount<=0){a.Window.clearUnreadMessages()}else{a.Window.renderUnreadMessages(a.Window._unreadMessagesCount)}},clearUnreadMessages:function(){a.Window._unreadMessagesCount=0;document.title=a.Window._plainTitle},renderUnreadMessages:function(c){document.title=Candy.View.Template.Window.unreadmessages.replace("{{count}}",c).replace("{{title}}",a.Window._plainTitle)},onFocus:function(){a.Window._hasFocus=true;if(Candy.View.getCurrent().roomJid){a.Room.setFocusToForm(Candy.View.getCurrent().roomJid);a.Chat.clearUnreadMessages(Candy.View.getCurrent().roomJid)}},onBlur:function(){a.Window._hasFocus=false}};a.Chat={rooms:[],addTab:function(d,c,e){var h=Candy.Util.jidToId(d),f=Mustache.to_html(Candy.View.Template.Chat.tab,{roomJid:d,roomId:h,name:c||Strophe.getNodeFromJid(d),privateUserChat:function(){return e==="chat"},roomType:e}),g=b(f).appendTo("#chat-tabs");g.click(a.Chat.tabClick);b("a.close",g).click(a.Chat.tabClose);a.Chat.fitTabs()},getTab:function(c){return b("#chat-tabs").children('li[data-roomjid="'+c+'"]')},removeTab:function(c){a.Chat.getTab(c).remove();a.Chat.fitTabs()},setActiveTab:function(c){b("#chat-tabs").children().each(function(){var d=b(this);if(d.attr("data-roomjid")===c){d.addClass("active")}else{d.removeClass("active")}})},increaseUnreadMessages:function(d){var c=this.getTab(d).find(".unread");c.show().text(c.text()!==""?parseInt(c.text(),10)+1:1);if(a.Chat.rooms[d].type==="chat"){a.Window.increaseUnreadMessages()}},clearUnreadMessages:function(d){var c=a.Chat.getTab(d).find(".unread");a.Window.reduceUnreadMessages(c.text());c.hide().text("")},tabClick:function(d){var c=Candy.View.getCurrent().roomJid;a.Chat.rooms[c].scrollPosition=a.Room.getPane(c,".message-pane-wrapper").scrollTop();a.Room.show(b(this).attr("data-roomjid"));d.preventDefault()},tabClose:function(d){var c=b(this).parent().attr("data-roomjid");if(a.Chat.rooms[c].type==="chat"){a.Room.close(c)}else{Candy.Core.Action.Jabber.Room.Leave(c)}return false},allTabsClosed:function(){Candy.Core.disconnect();a.Chat.Toolbar.hide();return},fitTabs:function(){var g=b("#chat-tabs").innerWidth(),f=0,e=b("#chat-tabs").children();e.each(function(){f+=b(this).css({width:"auto",overflow:"visible"}).outerWidth(true)});if(f>g){var c=e.outerWidth(true)-e.width(),d=Math.floor((g)/e.length)-c;e.css({width:d,overflow:"hidden"})}},updateToolbar:function(c){b("#chat-toolbar").find(".context").click(function(d){a.Chat.Context.show(d.currentTarget,c);d.stopPropagation()});Candy.View.Pane.Chat.Toolbar.updateUsercount(Candy.View.Pane.Chat.rooms[c].usercount)},adminMessage:function(d,e){if(Candy.View.getCurrent().roomJid){var c=Mustache.to_html(Candy.View.Template.Chat.adminMessage,{subject:d,message:e,sender:b.i18n._("administratorMessageSubject"),time:Candy.Util.localizedTime(new Date().toGMTString())});b("#chat-rooms").children().each(function(){a.Room.appendToMessagePane(b(this).attr("data-roomjid"),c)});a.Room.scrollToBottom(Candy.View.getCurrent().roomJid);Candy.View.Event.Chat.onAdminMessage({subject:d,message:e})}},infoMessage:function(c,d,e){a.Chat.onInfoMessage(c,d,e)},onInfoMessage:function(c,e,f){if(Candy.View.getCurrent().roomJid){var d=Mustache.to_html(Candy.View.Template.Chat.infoMessage,{subject:e,message:b.i18n._(f),time:Candy.Util.localizedTime(new Date().toGMTString())});a.Room.appendToMessagePane(c,d);if(Candy.View.getCurrent().roomJid===c){a.Room.scrollToBottom(Candy.View.getCurrent().roomJid)}}},Toolbar:{show:function(){b("#chat-toolbar").show()},hide:function(){b("#chat-toolbar").hide()},playSound:function(){a.Chat.Toolbar.onPlaySound()},onPlaySound:function(){var c=document.getElementById("chat-sound-player");c.SetVariable("method:stop","");c.SetVariable("method:play","")},onSoundControlClick:function(){var c=b("#chat-sound-control");if(c.hasClass("checked")){a.Chat.Toolbar.playSound=function(){};Candy.Util.setCookie("candy-nosound","1",365)}else{a.Chat.Toolbar.playSound=function(){a.Chat.Toolbar.onPlaySound()};Candy.Util.deleteCookie("candy-nosound")}c.toggleClass("checked")},onAutoscrollControlClick:function(){var c=b("#chat-autoscroll-control");if(c.hasClass("checked")){a.Room.scrollToBottom=function(d){a.Room.onScrollToStoredPosition(d)};a.Window.autoscroll=false}else{a.Room.scrollToBottom=function(d){a.Room.onScrollToBottom(d)};a.Room.scrollToBottom(Candy.View.getCurrent().roomJid);a.Window.autoscroll=true}c.toggleClass("checked")},onStatusMessageControlClick:function(){var c=b("#chat-statusmessage-control");if(c.hasClass("checked")){a.Chat.infoMessage=function(){};Candy.Util.setCookie("candy-nostatusmessages","1",365)}else{a.Chat.infoMessage=function(d,e,f){a.Chat.onInfoMessage(d,e,f)};Candy.Util.deleteCookie("candy-nostatusmessages")}c.toggleClass("checked")},updateUsercount:function(c){b("#chat-usercount").text(c)}},Modal:{show:function(d,e,c){if(e){a.Chat.Modal.showCloseControl()}else{a.Chat.Modal.hideCloseControl()}if(c){a.Chat.Modal.showSpinner()}else{a.Chat.Modal.hideSpinner()}b("#chat-modal-body").html(d);b("#chat-modal").fadeIn("fast");b("#chat-modal-overlay").show()},hide:function(c){b("#chat-modal").fadeOut("fast",function(){b("#chat-modal-body").text("");b("#chat-modal-overlay").hide()});b(document).keydown(function(d){if(d.which===27){d.preventDefault()}});if(c){c()}},showSpinner:function(){b("#chat-modal-spinner").show()},hideSpinner:function(){b("#chat-modal-spinner").hide()},showCloseControl:function(){b("#admin-message-cancel").show().click(function(c){a.Chat.Modal.hide();c.preventDefault()});b(document).keydown(function(c){if(c.which===27){a.Chat.Modal.hide();c.preventDefault()}})},hideCloseControl:function(){b("#admin-message-cancel").hide().click(function(){})},showLoginForm:function(d,c){Candy.View.Pane.Chat.Modal.show((d?d:"")+Mustache.to_html(Candy.View.Template.Login.form,{_labelUsername:b.i18n._("labelUsername"),_labelPassword:b.i18n._("labelPassword"),_loginSubmit:b.i18n._("loginSubmit"),displayPassword:!Candy.Core.isAnonymousConnection(),displayUsername:Candy.Core.isAnonymousConnection()||!c,presetJid:c?c:false}));b("#login-form").submit(function(g){var h=b("#username").val(),e=b("#password").val();if(!Candy.Core.isAnonymousConnection()){var f=Candy.Core.getUser()&&h.indexOf("@")<0?h+"@"+Strophe.getDomainFromJid(Candy.Core.getUser().getJid()):h;if(f.indexOf("@")<0&&!Candy.Core.getUser()){Candy.View.Pane.Chat.Modal.showLoginForm(b.i18n._("loginInvalid"))}else{Candy.Core.connect(f,e)}}else{Candy.Core.connect(c,null,h)}return false})}},Tooltip:{show:function(g,f){var h=b("#tooltip"),i=b(g.currentTarget);if(!f){f=i.attr("data-tooltip")}if(h.length===0){var d=Mustache.to_html(Candy.View.Template.Chat.tooltip);b("#chat-pane").append(d);h=b("#tooltip")}b("#context-menu").hide();h.stop(false,true);h.children("div").html(f);var j=i.offset(),c=Candy.Util.getPosLeftAccordingToWindowBounds(h,j.left),e=Candy.Util.getPosTopAccordingToWindowBounds(h,j.top);h.css({left:c.px,top:e.px,backgroundPosition:c.backgroundPositionAlignment+" "+e.backgroundPositionAlignment}).fadeIn("fast");i.mouseleave(function(k){k.stopPropagation();b("#tooltip").stop(false,true).fadeOut("fast",function(){b(this).css({top:0,left:0})})})}},Context:{init:function(){if(b("#context-menu").length===0){var c=Mustache.to_html(Candy.View.Template.Chat.Context.menu);b("#chat-pane").append(c);b("#context-menu").mouseleave(function(){b(this).fadeOut("fast")})}},show:function(e,p,h){e=b(e);var f=a.Chat.rooms[p].id,d=b("#context-menu"),o=b("ul li",d);b("#tooltip").hide();if(!h){h=Candy.Core.getUser()}o.remove();var k=this.getMenuLinks(p,h,e),c,l=function(r,q){return function(s){s.data.callback(s,r,q);b("#context-menu").hide()}};for(c in k){if(k.hasOwnProperty(c)){var n=k[c],j=Mustache.to_html(Candy.View.Template.Chat.Context.menulinks,{roomId:f,"class":n["class"],id:c,label:n.label});b("ul",d).append(j);b("#context-menu-"+c).bind("click",n,l(p,h))}}if(c){var m=e.offset(),g=Candy.Util.getPosLeftAccordingToWindowBounds(d,m.left),i=Candy.Util.getPosTopAccordingToWindowBounds(d,m.top);d.css({left:g.px,top:i.px,backgroundPosition:g.backgroundPositionAlignment+" "+i.backgroundPositionAlignment});d.fadeIn("fast");Candy.View.Event.Roster.afterContextMenu({roomJid:p,user:h,element:d});return true}},getMenuLinks:function(d,c,e){var f=b.extend(this.initialMenuLinks(e),Candy.View.Event.Roster.onContextMenu({roomJid:d,user:c,elem:e})),g;for(g in f){if(f.hasOwnProperty(g)&&f[g].requiredPermission!==undefined&&!f[g].requiredPermission(c,a.Room.getUser(d),e)){delete f[g]}}return f},initialMenuLinks:function(){return{"private":{requiredPermission:function(c,d){return d.getNick()!==c.getNick()&&Candy.Core.getRoom(Candy.View.getCurrent().roomJid)&&!Candy.Core.getUser().isInPrivacyList("ignore",c.getJid())},"class":"private",label:b.i18n._("privateActionLabel"),callback:function(f,d,c){b("#user-"+Candy.Util.jidToId(d)+"-"+Candy.Util.jidToId(c.getJid())).click()}},ignore:{requiredPermission:function(c,d){return d.getNick()!==c.getNick()&&!Candy.Core.getUser().isInPrivacyList("ignore",c.getJid())},"class":"ignore",label:b.i18n._("ignoreActionLabel"),callback:function(f,d,c){Candy.View.Pane.Room.ignoreUser(d,c.getJid())}},unignore:{requiredPermission:function(c,d){return d.getNick()!==c.getNick()&&Candy.Core.getUser().isInPrivacyList("ignore",c.getJid())},"class":"unignore",label:b.i18n._("unignoreActionLabel"),callback:function(f,d,c){Candy.View.Pane.Room.unignoreUser(d,c.getJid())}},kick:{requiredPermission:function(c,d){return d.getNick()!==c.getNick()&&d.isModerator()&&!c.isModerator()},"class":"kick",label:b.i18n._("kickActionLabel"),callback:function(f,d,c){a.Chat.Modal.show(Mustache.to_html(Candy.View.Template.Chat.Context.contextModalForm,{_label:b.i18n._("reason"),_submit:b.i18n._("kickActionLabel")}),true);b("#context-modal-field").focus();b("#context-modal-form").submit(function(e){Candy.Core.Action.Jabber.Room.Admin.UserAction(d,c.getJid(),"kick",b("#context-modal-field").val());a.Chat.Modal.hide();return false})}},ban:{requiredPermission:function(c,d){return d.getNick()!==c.getNick()&&d.isModerator()&&!c.isModerator()},"class":"ban",label:b.i18n._("banActionLabel"),callback:function(f,d,c){a.Chat.Modal.show(Mustache.to_html(Candy.View.Template.Chat.Context.contextModalForm,{_label:b.i18n._("reason"),_submit:b.i18n._("banActionLabel")}),true);b("#context-modal-field").focus();b("#context-modal-form").submit(function(g){Candy.Core.Action.Jabber.Room.Admin.UserAction(d,c.getJid(),"ban",b("#context-modal-field").val());a.Chat.Modal.hide();return false})}},subject:{requiredPermission:function(c,d){return d.getNick()===c.getNick()&&d.isModerator()},"class":"subject",label:b.i18n._("setSubjectActionLabel"),callback:function(f,d,c){a.Chat.Modal.show(Mustache.to_html(Candy.View.Template.Chat.Context.contextModalForm,{_label:b.i18n._("subject"),_submit:b.i18n._("setSubjectActionLabel")}),true);b("#context-modal-field").focus();b("#context-modal-form").submit(function(g){Candy.Core.Action.Jabber.Room.Admin.SetSubject(d,b("#context-modal-field").val());a.Chat.Modal.hide();g.preventDefault()})}}}},showEmoticonsMenu:function(h){h=b(h);var k=h.offset(),j=b("#context-menu"),g=b("ul",j),e="",d;b("#tooltip").hide();for(d=Candy.Util.Parser.emoticons.length-1;d>=0;d--){e='<img src="'+Candy.Util.Parser._emoticonPath+Candy.Util.Parser.emoticons[d].image+'" alt="'+Candy.Util.Parser.emoticons[d].plain+'" />'+e}g.html('<li class="emoticons">'+e+"</li>");g.find("img").click(function(){var i=Candy.View.Pane.Room.getPane(Candy.View.getCurrent().roomJid,".message-form").children(".field"),m=i.val(),l=b(this).attr("alt")+" ";i.val(m?m+" "+l:l).focus()});var c=Candy.Util.getPosLeftAccordingToWindowBounds(j,k.left),f=Candy.Util.getPosTopAccordingToWindowBounds(j,k.top);j.css({left:c.px,top:f.px,backgroundPosition:c.backgroundPositionAlignment+" "+f.backgroundPositionAlignment});j.fadeIn("fast");return true}}};a.Room={init:function(d,c,e){e=e||"groupchat";if(Candy.Util.isEmptyObject(a.Chat.rooms)){a.Chat.Toolbar.show()}var f=Candy.Util.jidToId(d);a.Chat.rooms[d]={id:f,usercount:0,name:c,type:e,messageCount:0,scrollPosition:-1};b("#chat-rooms").append(Mustache.to_html(Candy.View.Template.Room.pane,{roomId:f,roomJid:d,roomType:e,form:{_messageSubmit:b.i18n._("messageSubmit")},roster:{_userOnline:b.i18n._("userOnline")}},{roster:Candy.View.Template.Roster.pane,messages:Candy.View.Template.Message.pane,form:Candy.View.Template.Room.form}));a.Chat.addTab(d,c,e);a.Room.getPane(d,".message-form").submit(a.Message.submit);Candy.View.Event.Room.onAdd({roomJid:d,type:e,element:a.Room.getPane(d)});return f},show:function(c){var d=a.Chat.rooms[c].id;b(".room-pane").each(function(){var e=b(this);if(e.attr("id")===("chat-room-"+d)){e.show();Candy.View.getCurrent().roomJid=c;a.Chat.updateToolbar(c);a.Chat.setActiveTab(c);a.Chat.clearUnreadMessages(c);a.Room.setFocusToForm(c);a.Room.scrollToBottom(c);Candy.View.Event.Room.onShow({roomJid:c,element:e})}else{e.hide();Candy.View.Event.Room.onHide({roomJid:c,element:e})}})},setSubject:function(c,e){var d=Mustache.to_html(Candy.View.Template.Room.subject,{subject:e,roomName:a.Chat.rooms[c].name,_roomSubject:b.i18n._("roomSubject"),time:Candy.Util.localizedTime(new Date().toGMTString())});a.Room.appendToMessagePane(c,d);a.Room.scrollToBottom(c);Candy.View.Event.Room.onSubjectChange({roomJid:c,element:a.Room.getPane(c),subject:e})},close:function(c){a.Chat.removeTab(c);a.Window.clearUnreadMessages();a.Room.getPane(c).remove();var d=b("#chat-rooms").children();if(Candy.View.getCurrent().roomJid===c){Candy.View.getCurrent().roomJid=null;if(d.length===0){a.Chat.allTabsClosed()}else{a.Room.show(d.last().attr("data-roomjid"))}}delete a.Chat.rooms[c];Candy.View.Event.Room.onClose({roomJid:c})},appendToMessagePane:function(c,d){a.Room.getPane(c,".message-pane").append(d);a.Chat.rooms[c].messageCount++;a.Room.sliceMessagePane(c)},sliceMessagePane:function(c){if(a.Window.autoscroll){var d=Candy.View.getOptions().messages;if(a.Chat.rooms[c].messageCount>d.limit){a.Room.getPane(c,".message-pane").children().slice(0,d.remove*2).remove();a.Chat.rooms[c].messageCount-=d.remove}}},scrollToBottom:function(c){a.Room.onScrollToBottom(c)},onScrollToBottom:function(c){var d=a.Room.getPane(c,".message-pane-wrapper");d.scrollTop(d.prop("scrollHeight"))},onScrollToStoredPosition:function(c){if(a.Chat.rooms[c].scrollPosition>-1){var d=a.Room.getPane(c,".message-pane-wrapper");d.scrollTop(a.Chat.rooms[c].scrollPosition);a.Chat.rooms[c].scrollPosition=-1}},setFocusToForm:function(c){var f=a.Room.getPane(c,".message-form");if(f){try{f.children(".field")[0].focus()}catch(d){}}},setUser:function(d,c){a.Chat.rooms[d].user=c;var f=a.Room.getPane(d),e=b("#chat-pane");f.attr("data-userjid",c.getJid());if(c.isModerator()){if(c.getRole()===c.ROLE_MODERATOR){e.addClass("role-moderator")}if(c.getAffiliation()===c.AFFILIATION_OWNER){e.addClass("affiliation-owner")}}else{e.removeClass("role-moderator affiliation-owner")}a.Chat.Context.init()},getUser:function(c){return a.Chat.rooms[c].user},ignoreUser:function(c,d){Candy.Core.Action.Jabber.Room.IgnoreUnignore(d);Candy.View.Pane.Room.addIgnoreIcon(c,d)},unignoreUser:function(c,d){Candy.Core.Action.Jabber.Room.IgnoreUnignore(d);Candy.View.Pane.Room.removeIgnoreIcon(c,d)},addIgnoreIcon:function(c,d){if(Candy.View.Pane.Chat.rooms[d]){b("#user-"+Candy.View.Pane.Chat.rooms[d].id+"-"+Candy.Util.jidToId(d)).addClass("status-ignored")}if(Candy.View.Pane.Chat.rooms[Strophe.getBareJidFromJid(c)]){b("#user-"+Candy.View.Pane.Chat.rooms[Strophe.getBareJidFromJid(c)].id+"-"+Candy.Util.jidToId(d)).addClass("status-ignored")}},removeIgnoreIcon:function(c,d){if(Candy.View.Pane.Chat.rooms[d]){b("#user-"+Candy.View.Pane.Chat.rooms[d].id+"-"+Candy.Util.jidToId(d)).removeClass("status-ignored")}if(Candy.View.Pane.Chat.rooms[Strophe.getBareJidFromJid(c)]){b("#user-"+Candy.View.Pane.Chat.rooms[Strophe.getBareJidFromJid(c)].id+"-"+Candy.Util.jidToId(d)).removeClass("status-ignored")}},getPane:function(c,d){if(a.Chat.rooms[c]){if(d){if(a.Chat.rooms[c]["pane-"+d]){return a.Chat.rooms[c]["pane-"+d]}else{a.Chat.rooms[c]["pane-"+d]=b("#chat-room-"+a.Chat.rooms[c].id).find(d);return a.Chat.rooms[c]["pane-"+d]}}else{return b("#chat-room-"+a.Chat.rooms[c].id)}}}};a.PrivateRoom={open:function(e,c,f,g){var d=g?Candy.Core.getUser():a.Room.getUser(Strophe.getBareJidFromJid(e));if(Candy.Core.getUser().isInPrivacyList("ignore",e)){return false}if(!a.Chat.rooms[e]){a.Room.init(e,c,"chat")}if(f){a.Room.show(e)}a.Roster.update(e,new Candy.Core.ChatUser(e,c),"join",d);a.Roster.update(e,d,"join",d);a.PrivateRoom.setStatus(e,"join");if(g){a.Chat.infoMessage(e,b.i18n._("presenceUnknownWarningSubject"),b.i18n._("presenceUnknownWarning"))}Candy.View.Event.Room.onAdd({roomJid:e,type:"chat",element:a.Room.getPane(e)})},setStatus:function(d,c){var e=a.Room.getPane(d,".message-form");if(c==="join"){a.Chat.getTab(d).addClass("online").removeClass("offline");e.children(".field").removeAttr("disabled");e.children(".submit").removeAttr("disabled");a.Chat.getTab(d)}else{a.Chat.getTab(d).addClass("offline").removeClass("online");e.children(".field").attr("disabled",true);e.children(".submit").attr("disabled",true)}}};a.Roster={update:function(n,i,h,e){var f=a.Chat.rooms[n].id,k=Candy.Util.jidToId(i.getJid()),c=-1;if(h==="join"){c=1;var j=Mustache.to_html(Candy.View.Template.Roster.user,{roomId:f,userId:k,userJid:i.getJid(),nick:i.getNick(),displayNick:Candy.Util.crop(i.getNick(),Candy.View.getOptions().crop.roster.displayNick),role:i.getRole(),affiliation:i.getAffiliation(),me:e!==undefined&&i.getNick()===e.getNick(),tooltipRole:b.i18n._("tooltipRole"),tooltipIgnored:b.i18n._("tooltipIgnored")}),m=b("#user-"+f+"-"+k);if(m.length<1){var d=false,l=a.Room.getPane(n,".roster-pane");if(l.children().length>0){var g=i.getNick().toUpperCase();l.children().each(function(){var o=b(this);if(o.attr("data-nick").toUpperCase()>g){o.before(j);d=true;return false}return true})}if(!d){l.append(j)}a.Roster.joinAnimation("user-"+f+"-"+k);if(e!==undefined&&i.getNick()!==e.getNick()&&a.Room.getUser(n)){if(a.Chat.rooms[n].type==="chat"){a.Chat.onInfoMessage(n,b.i18n._("userJoinedRoom",[i.getNick()]))}else{a.Chat.infoMessage(n,b.i18n._("userJoinedRoom",[i.getNick()]))}}}else{c=0;m.replaceWith(j);b("#user-"+f+"-"+k).css({opacity:1}).show()}if(e!==undefined&&e.getNick()===i.getNick()){a.Room.setUser(n,i)}else{b("#user-"+f+"-"+k).click(a.Roster.userClick)}b("#user-"+f+"-"+k+" .context").click(function(o){a.Chat.Context.show(o.currentTarget,n,i);o.stopPropagation()});if(e!==undefined&&e.isInPrivacyList("ignore",i.getJid())){Candy.View.Pane.Room.addIgnoreIcon(n,i.getJid())}}else{if(h==="leave"){a.Roster.leaveAnimation("user-"+f+"-"+k);if(a.Chat.rooms[n].type==="chat"){a.Chat.onInfoMessage(n,b.i18n._("userLeftRoom",[i.getNick()]))}else{a.Chat.infoMessage(n,b.i18n._("userLeftRoom",[i.getNick()]))}}else{if(h==="kick"){a.Roster.leaveAnimation("user-"+f+"-"+k);a.Chat.onInfoMessage(n,b.i18n._("userHasBeenKickedFromRoom",[i.getNick()]))}else{if(h==="ban"){a.Roster.leaveAnimation("user-"+f+"-"+k);a.Chat.onInfoMessage(n,b.i18n._("userHasBeenBannedFromRoom",[i.getNick()]))}}}}Candy.View.Pane.Chat.rooms[n].usercount+=c;if(n===Candy.View.getCurrent().roomJid){Candy.View.Pane.Chat.Toolbar.updateUsercount(Candy.View.Pane.Chat.rooms[n].usercount)}Candy.View.Event.Roster.onUpdate({roomJid:n,user:i,action:h,element:b("#user-"+f+"-"+k)})},userClick:function(){var c=b(this);a.PrivateRoom.open(c.attr("data-jid"),c.attr("data-nick"),true)},joinAnimation:function(c){b("#"+c).stop(true).slideDown("normal",function(){b(this).animate({opacity:1})})},leaveAnimation:function(c){b("#"+c).stop(true).attr("id","#"+c+"-leaving").animate({opacity:0},{complete:function(){b(this).slideUp("normal",function(){b(this).remove()})}})}};a.Message={submit:function(e){var c=Candy.View.Pane.Chat.rooms[Candy.View.getCurrent().roomJid].type,d=b(this).children(".field").val().substring(0,1000);d=Candy.View.Event.Message.beforeSend(d);Candy.Core.Action.Jabber.Room.Message(Candy.View.getCurrent().roomJid,d,c);if(c==="chat"&&d){a.Message.show(Candy.View.getCurrent().roomJid,a.Room.getUser(Candy.View.getCurrent().roomJid).getNick(),d)}b(this).children(".field").val("").focus();e.preventDefault()},show:function(c,d,g,h){g=Candy.Util.Parser.all(g.substring(0,1000));g=Candy.View.Event.Message.beforeShow({roomJid:c,nick:d,message:g});if(!g){return}var e=Mustache.to_html(Candy.View.Template.Message.item,{name:d,displayName:Candy.Util.crop(d,Candy.View.getOptions().crop.message.displayName),message:g,time:Candy.Util.localizedTime(h||new Date().toGMTString())});a.Room.appendToMessagePane(c,e);var f=a.Room.getPane(c,".message-pane").children().last();f.find("a.name").click(function(i){i.preventDefault();if(d!==a.Room.getUser(Candy.View.getCurrent().roomJid).getNick()&&Candy.Core.getRoom(c).getRoster().get(c+"/"+d)){Candy.View.Pane.PrivateRoom.open(c+"/"+d,d,true)}});if(Candy.View.getCurrent().roomJid!==c||!a.Window.hasFocus()){a.Chat.increaseUnreadMessages(c);if(Candy.View.Pane.Chat.rooms[c].type==="chat"&&!a.Window.hasFocus()){a.Chat.Toolbar.playSound()}}if(Candy.View.getCurrent().roomJid===c){a.Room.scrollToBottom(c)}Candy.View.Event.Message.onShow({roomJid:c,element:f,nick:d,message:g})}};return a}(Candy.View.Pane||{},jQuery));Candy.View.Template=(function(a){a.Window={unreadmessages:"({{count}}) {{title}}"};a.Chat={pane:'<div id="chat-pane">{{> tabs}}{{> toolbar}}{{> rooms}}</div>{{> modal}}',rooms:'<div id="chat-rooms" class="rooms"></div>',tabs:'<ul id="chat-tabs"></ul>',tab:'<li class="roomtype-{{roomType}}" data-roomjid="{{roomJid}}" data-roomtype="{{roomType}}"><a href="#" class="label">{{#privateUserChat}}@{{/privateUserChat}}{{name}}</a><a href="#" class="transition"></a><a href="#" class="close">\u00D7</a><small class="unread"></small></li>',modal:'<div id="chat-modal"><a id="admin-message-cancel" class="close" href="#">\u00D7</a><span id="chat-modal-body"></span><img src="{{resourcesPath}}img/modal-spinner.gif" id="chat-modal-spinner" /></div><div id="chat-modal-overlay"></div>',adminMessage:'<dt>{{time}}</dt><dd class="adminmessage"><span class="label">{{sender}}</span>{{subject}} {{message}}</dd>',infoMessage:'<dt>{{time}}</dt><dd class="infomessage">{{subject}} {{message}}</dd>',toolbar:'<ul id="chat-toolbar"><li id="emoticons-icon" data-tooltip="{{tooltipEmoticons}}"></li><li id="chat-sound-control" class="checked" data-tooltip="{{tooltipSound}}">{{> soundcontrol}}</li><li id="chat-autoscroll-control" class="checked" data-tooltip="{{tooltipAutoscroll}}"></li><li class="checked" id="chat-statusmessage-control" data-tooltip="{{tooltipStatusmessage}}"></li><li class="context" data-tooltip="{{tooltipAdministration}}"></li><li class="usercount" data-tooltip="{{tooltipUsercount}}"><span id="chat-usercount"></span></li></ul>',soundcontrol:'<script type="text/javascript">var audioplayerListener = new Object(); audioplayerListener.onInit = function() { };<\/script><object id="chat-sound-player" type="application/x-shockwave-flash" data="{{resourcesPath}}audioplayer.swf" width="0" height="0"><param name="movie" value="{{resourcesPath}}audioplayer.swf" /><param name="AllowScriptAccess" value="always" /><param name="FlashVars" value="listener=audioplayerListener&amp;mp3={{resourcesPath}}notify.mp3" /></object>',Context:{menu:'<div id="context-menu"><ul></ul></div>',menulinks:'<li class="{{class}}" id="context-menu-{{id}}">{{label}}</li>',contextModalForm:'<form action="#" id="context-modal-form"><label for="context-modal-label">{{_label}}</label><input type="text" name="contextModalField" id="context-modal-field" /><input type="submit" class="button" name="send" value="{{_submit}}" /></form>',adminMessageReason:'<a id="admin-message-cancel" class="close" href="#">×</a><p>{{_action}}</p>{{#reason}}<p>{{_reason}}</p>{{/reason}}'},tooltip:'<div id="tooltip"><div></div></div>'};a.Room={pane:'<div class="room-pane roomtype-{{roomType}}" id="chat-room-{{roomId}}" data-roomjid="{{roomJid}}" data-roomtype="{{roomType}}">{{> roster}}{{> messages}}{{> form}}</div>',subject:'<dt>{{time}}</dt><dd class="subject"><span class="label">{{roomName}}</span>{{_roomSubject}} {{subject}}</dd>',form:'<div class="message-form-wrapper"></div><form method="post" class="message-form"><input name="message" class="field" type="text" autocomplete="off" maxlength="1000" /><input type="submit" class="submit" name="submit" value="{{_messageSubmit}}" /></form>'};a.Roster={pane:'<div class="roster-pane"></div>',user:'<div class="user role-{{role}} affiliation-{{affiliation}}{{#me}} me{{/me}}" id="user-{{roomId}}-{{userId}}" data-jid="{{userJid}}" data-nick="{{nick}}" data-role="{{role}}" data-affiliation="{{affiliation}}"><div class="label">{{displayNick}}</div><ul><li class="context" id="context-{{roomId}}-{{userId}}"></li><li class="role role-{{role}} affiliation-{{affiliation}}" data-tooltip="{{tooltipRole}}"></li><li class="ignore" data-tooltip="{{tooltipIgnored}}"></li></ul></div>'};a.Message={pane:'<div class="message-pane-wrapper"><dl class="message-pane"></dl></div>',item:'<dt>{{time}}</dt><dd><span class="label"><a href="#" class="name">{{displayName}}</a></span>{{{message}}}</dd>'};a.Login={form:'<form method="post" id="login-form" class="login-form">{{#displayUsername}}<label for="username">{{_labelUsername}}</label><input type="text" id="username" name="username"/>{{/displayUsername}}{{#presetJid}}<input type="hidden" id="username" name="username" value="{{presetJid}}"/>{{/presetJid}}{{#displayPassword}}<label for="password">{{_labelPassword}}</label><input type="password" id="password" name="password" />{{/displayPassword}}<input type="submit" class="button" value="{{_loginSubmit}}" /></form>'};return a}(Candy.View.Template||{}));Candy.View.Translation={en:{status:"Status: %s",statusConnecting:"Connecting...",statusConnected:"Connected",statusDisconnecting:"Disconnecting...",statusDisconnected:"Disconnected",statusAuthfail:"Authentication failed",roomSubject:"Subject:",messageSubmit:"Send",labelUsername:"Username:",labelPassword:"Password:",loginSubmit:"Login",loginInvalid:"Invalid JID",reason:"Reason:",subject:"Subject:",reasonWas:"Reason was: %s.",kickActionLabel:"Kick",youHaveBeenKickedBy:"You have been kicked from %s by %s",banActionLabel:"Ban",youHaveBeenBannedBy:"You have been banned from %s by %s",privateActionLabel:"Private chat",ignoreActionLabel:"Ignore",unignoreActionLabel:"Unignore",setSubjectActionLabel:"Change Subject",administratorMessageSubject:"Administrator",userJoinedRoom:"%s joined the room.",userLeftRoom:"%s left the room.",userHasBeenKickedFromRoom:"%s has been kicked from the room.",userHasBeenBannedFromRoom:"%s has been banned from the room.",presenceUnknownWarningSubject:"Notice:",presenceUnknownWarning:"This user might be offline. We can't track his presence.",dateFormat:"dd.mm.yyyy",timeFormat:"HH:MM:ss",tooltipRole:"Moderator",tooltipIgnored:"You ignore this user",tooltipEmoticons:"Emoticons",tooltipSound:"Play sound for new private messages",tooltipAutoscroll:"Autoscroll",tooltipStatusmessage:"Display status messages",tooltipAdministration:"Room Administration",tooltipUsercount:"Room Occupants",raptorMessageBlocked:"Please do not spam. You have been blocked for a short-time."},de:{status:"Status: %s",statusConnecting:"Verbinden...",statusConnected:"Verbunden",statusDisconnecting:"Verbindung trennen...",statusDisconnected:"Verbindung getrennt",statusAuthfail:"Authentifizierung fehlgeschlagen",roomSubject:"Thema:",messageSubmit:"Senden",labelUsername:"Benutzername:",labelPassword:"Passwort:",loginSubmit:"Anmelden",loginInvalid:"Ungültige JID",reason:"Begründung:",subject:"Titel:",reasonWas:"Begründung: %s.",kickActionLabel:"Kick",youHaveBeenKickedBy:"Du wurdest soeben aus dem Raum %s gekickt (%s)",banActionLabel:"Ban",youHaveBeenBannedBy:"Du wurdest soeben aus dem Raum %s verbannt (%s)",privateActionLabel:"Privater Chat",ignoreActionLabel:"Ignorieren",unignoreActionLabel:"Nicht mehr ignorieren",setSubjectActionLabel:"Thema ändern",administratorMessageSubject:"Administrator",userJoinedRoom:"%s hat soeben den Raum betreten.",userLeftRoom:"%s hat soeben den Raum verlassen.",userHasBeenKickedFromRoom:"%s ist aus dem Raum gekickt worden.",userHasBeenBannedFromRoom:"%s ist aus dem Raum verbannt worden.",presenceUnknownWarningSubject:"Hinweis:",presenceUnknownWarning:"Dieser Benutzer könnte bereits abgemeldet sein. Wir können seine Anwesenheit nicht verfolgen.",dateFormat:"dd.mm.yyyy",timeFormat:"HH:MM:ss",tooltipRole:"Moderator",tooltipIgnored:"Du ignorierst diesen Benutzer",tooltipEmoticons:"Smileys",tooltipSound:"Ton abspielen bei neuen privaten Nachrichten",tooltipAutoscroll:"Autoscroll",tooltipStatusmessage:"Statusnachrichten anzeigen",tooltipAdministration:"Raum Administration",tooltipUsercount:"Anzahl Benutzer im Raum",raptorMessageBlocked:"Bitte nicht spammen. Du wurdest für eine kurze Zeit blockiert."},fr:{status:"Status: %s",statusConnecting:"Connecter...",statusConnected:"Connecté.",statusDisconnecting:"Déconnecter....",statusDisconnected:"Déconnecté.",statusAuthfail:"Authentification a échoué",roomSubject:"Sujet:",messageSubmit:"Envoyer",labelUsername:"Nom d'utilisateur:",labelPassword:"Mot de passe:",loginSubmit:"Inscription",loginInvalid:"JID invalide",reason:"Justification:",subject:"Titre:",reasonWas:"Justification: %s.",kickActionLabel:"Kick",youHaveBeenKickedBy:"Tu as été expulsé (%s)",banActionLabel:"Ban",youHaveBeenBannedBy:"Tu as été banni (%s)",privateActionLabel:"Chat privé",ignoreActionLabel:"Ignorer",unignoreActionLabel:"Ne plus ignorer",setSubjectActionLabel:"Changer le sujet",administratorMessageSubject:"Administrateur",userJoinedRoom:"%s vient d'entrer dans le salon.",userLeftRoom:"%s vient de quitter le salon.",userHasBeenKickedFromRoom:"%s a été expulsé du salon.",userHasBeenBannedFromRoom:"%s a été banni du salon.",presenceUnknownWarningSubject:"Note:",presenceUnknownWarning:"Cet utilisateur n'est malheureusement plus connecté, le message ne sera pas envoyé.",dateFormat:"dd.mm.yyyy",timeFormat:"HH:MM:ss",tooltipRole:"Modérateur",tooltipIgnored:"Tu ignores cette personne",tooltipEmoticons:"Smileys",tooltipSound:"Jouer un son lorsque tu reçois de nouveaux messages privés",tooltipAutoscroll:"Auto-defilement",tooltipStatusmessage:"Messages d'état",tooltipAdministration:"Administrer le salon",tooltipUsercount:"Nombre d'utilisateurs dans le salon",raptorMessageBlocked:"S'il te plaît, pas de spam. Tu as été bloqué pendant une courte période.."},nl:{status:"Status: %s",statusConnecting:"Verbinding maken...",statusConnected:"Verbinding is gereed",statusDisconnecting:"Verbinding verbreken...",statusDisconnected:"Verbinding is verbroken",statusAuthfail:"Authenticatie is mislukt",roomSubject:"Onderwerp:",messageSubmit:"Verstuur",labelUsername:"Gebruikersnaam:",labelPassword:"Wachtwoord:",loginSubmit:"Inloggen",loginInvalid:"JID is onjuist",reason:"Reden:",subject:"Onderwerp:",reasonWas:"De reden was: %s.",kickActionLabel:"Verwijderen",youHaveBeenKickedBy:"Je bent verwijderd van %s door %s",banActionLabel:"Blokkeren",youHaveBeenBannedBy:"Je bent geblokkeerd van %s door %s",privateActionLabel:"Prive gesprek",ignoreActionLabel:"Negeren",unignoreActionLabel:"Niet negeren",setSubjectActionLabel:"Onderwerp wijzigen",administratorMessageSubject:"Beheerder",userJoinedRoom:"%s komt de chat binnen.",userLeftRoom:"%s heeft de chat verlaten.",userHasBeenKickedFromRoom:"%s is verwijderd.",userHasBeenBannedFromRoom:"%s is geblokkeerd.",presenceUnknownWarningSubject:"Mededeling:",presenceUnknownWarning:"Deze gebruiker is waarschijnlijk offline, we kunnen zijn/haar aanwezigheid niet vaststellen.",dateFormat:"dd.mm.yyyy",timeFormat:"HH:MM:ss",tooltipRole:"Moderator",tooltipIgnored:"Je negeert deze gebruiker",tooltipEmoticons:"Emotie-iconen",tooltipSound:"Speel een geluid af bij nieuwe privé berichten.",tooltipAutoscroll:"Automatisch scrollen",tooltipStatusmessage:"Statusberichten weergeven",tooltipAdministration:"Instellingen",tooltipUsercount:"Gebruikers",raptorMessageBlocked:"Het is niet toegestaan om veel berichten naar de server te versturen. Je bent voor een korte periode geblokkeerd."},es:{status:"Estado: %s",statusConnecting:"Conectando...",statusConnected:"Conectado",statusDisconnecting:"Desconectando...",statusDisconnected:"Desconectado",statusAuthfail:"Falló la autenticación",roomSubject:"Asunto:",messageSubmit:"Enviar",labelUsername:"Usuario:",labelPassword:"Clave:",loginSubmit:"Entrar",loginInvalid:"JID no válido",reason:"Razón:",subject:"Asunto:",reasonWas:"La razón fue: %s.",kickActionLabel:"Expulsar",youHaveBeenKickedBy:"Has sido expulsado de %s por %s",banActionLabel:"Prohibir",youHaveBeenBannedBy:"Has sido expulsado permanentemente de %s por %s",privateActionLabel:"Chat privado",ignoreActionLabel:"Ignorar",unignoreActionLabel:"No ignorar",setSubjectActionLabel:"Cambiar asunto",administratorMessageSubject:"Administrador",userJoinedRoom:"%s se ha unido a la sala.",userLeftRoom:"%s ha dejado la sala.",userHasBeenKickedFromRoom:"%s ha sido expulsado de la sala.",userHasBeenBannedFromRoom:"%s ha sido expulsado permanentemente de la sala.",presenceUnknownWarningSubject:"Atención:",presenceUnknownWarning:"Éste usuario podría estar desconectado..",dateFormat:"dd.mm.yyyy",timeFormat:"HH:MM:ss",tooltipRole:"Moderador",tooltipIgnored:"Ignoras a éste usuario",tooltipEmoticons:"Emoticonos",tooltipSound:"Reproducir un sonido para nuevos mensajes privados",tooltipAutoscroll:"Desplazamiento automático",tooltipStatusmessage:"Mostrar mensajes de estado",tooltipAdministration:"Administración de la sala",tooltipUsercount:"Usuarios en la sala",raptorMessageBlocked:"Por favor, no hagas spam. Has sido bloqueado temporalmente."}}; \ No newline at end of file
diff --git a/src/candy.js b/src/candy.js
index 4926cc7..581621a 100644
--- a/src/candy.js
+++ b/src/candy.js
@@ -29,7 +29,7 @@ var Candy = (function(self, $) {
*/
self.about = {
name: 'Candy',
- version: '1.0.3'
+ version: '1.0.4'
};
/** Function: init
diff --git a/src/core.js b/src/core.js
index 5f1f28c..13c3037 100644
--- a/src/core.js
+++ b/src/core.js
@@ -34,6 +34,10 @@ Candy.Core = (function(self, Strophe, $) {
* Opened rooms, containing instances of Candy.Core.ChatRooms
*/
_rooms = {},
+ /** PrivateVariable: _anonymousConnection
+ * Set in <Candy.Core.connect> when jidOrHost doesn't contain a @-char.
+ */
+ _anonymousConnection = false,
/** PrivateVariable: _options
* Options:
* (Boolean) debug - Debug (Default: false)
@@ -93,7 +97,7 @@ Candy.Core = (function(self, Strophe, $) {
self.init = function(service, options) {
_service = service;
// Apply options
- $.extend(_options, options);
+ $.extend(true, _options, options);
// Enable debug logging
if(_options.debug) {
@@ -135,6 +139,7 @@ Candy.Core = (function(self, Strophe, $) {
* There are four different procedures to login:
* connect('JID', 'password') - Connect a registered user
* connect('domain') - Connect anonymously to the domain. The user should receive a random JID.
+ * connect('domain', null, 'nick') - Connect anonymously to the domain. The user should receive a random JID but with a nick set.
* connect('JID') - Show login form and prompt for password. JID input is hidden.
* connect() - Show login form and prompt for JID and password.
*
@@ -143,29 +148,38 @@ Candy.Core = (function(self, Strophe, $) {
*
* Parameters:
* (String) jidOrHost - JID or Host
- * (String) password - Password of the user
+ * (String) password - Password of the user
+ * (String) nick - Nick of the user. Set one if you want to anonymously connect but preset a nick. If jidOrHost is a domain
+ * and this param is not set, Candy will prompt for a nick.
*/
- self.connect = function(jidOrHost, password) {
+ self.connect = function(jidOrHost, password, nick) {
// Reset before every connection attempt to make sure reconnections work after authfail, alltabsclosed, ...
_connection.reset();
_registerEventHandlers();
+
+ _anonymousConnection = !_anonymousConnection ? jidOrHost && jidOrHost.indexOf("@") < 0 : true;
+
if(jidOrHost && password) {
// authentication
- _connection.connect(jidOrHost + '/' + Candy.about.name, password, Candy.Core.Event.Strophe.Connect);
+ _connection.connect(_getEscapedJidFromJid(jidOrHost) + '/' + Candy.about.name, password, Candy.Core.Event.Strophe.Connect);
_user = new self.ChatUser(jidOrHost, Strophe.getNodeFromJid(jidOrHost));
+ } else if(jidOrHost && nick) {
+ // anonymous connect
+ _connection.connect(_getEscapedJidFromJid(jidOrHost) + '/' + Candy.about.name, null, Candy.Core.Event.Strophe.Connect);
+ _user = new self.ChatUser(null, nick); // set jid to null because we'll later receive it
} else if(jidOrHost) {
- if(jidOrHost.indexOf("@") < 0) {
- // Not a JID, anonymous login
- _connection.connect(jidOrHost, null, Candy.Core.Event.Strophe.Connect);
- } else {
- // Most likely a JID, display login modal
- Candy.Core.Event.Login(jidOrHost);
- }
+ Candy.Core.Event.Login(jidOrHost);
} else {
// display login modal
Candy.Core.Event.Login();
}
};
+
+ _getEscapedJidFromJid = function(jid) {
+ var node = Strophe.getNodeFromJid(jid),
+ domain = Strophe.getDomainFromJid(jid);
+ return node ? Strophe.escapeNode(node) + '@' + domain : domain;
+ };
/** Function: attach
* Attach an already binded & connected session to the server
@@ -235,6 +249,16 @@ Candy.Core = (function(self, Strophe, $) {
return _rooms;
};
+ /** Function: isAnonymousConnection
+ * Returns true if <Candy.Core.connect> was first called with a domain instead of a jid as the first param.
+ *
+ * Returns:
+ * (Boolean)
+ */
+ self.isAnonymousConnection = function() {
+ return _anonymousConnection;
+ };
+
/** Function: getOptions
* Gets options
*
diff --git a/src/core/action.js b/src/core/action.js
index 74fbe6c..817d14d 100644
--- a/src/core/action.js
+++ b/src/core/action.js
@@ -106,20 +106,16 @@ Candy.Core.Action = (function(self, Strophe, $) {
},
/** Function: GetJidIfAnonymous
- * On anonymous login, initially we don't know the jid and as a result, Candy.Core._user is not set.
- * Check if user is not set & set it if if necessary.
+ * On anonymous login, initially we don't know the jid and as a result, Candy.Core._user doesn't have a jid.
+ * Check if user doesn't have a jid and get it if necessary from the connection.
*/
GetJidIfAnonymous: function() {
- if (!Candy.Core.getUser()) {
+ if (!Candy.Core.getUser().getJid()) {
Candy.Core.log("[Jabber] Anonymous login");
- var connection = Candy.Core.getConnection(),
- nick = connection.stream_id,
- jid = connection.jid;
- Candy.Core.setUser(new Candy.Core.ChatUser(jid, nick));
+ Candy.Core.getUser().data.jid = Candy.Core.getConnection().jid;
}
},
-
/** Class: Candy.Core.Action.Jabber.Room
* Room-specific commands
*/
@@ -176,7 +172,7 @@ Candy.Core.Action = (function(self, Strophe, $) {
if(msg === '') {
return false;
}
- Candy.Core.getConnection().muc.message(roomJid, undefined, msg, type);
+ Candy.Core.getConnection().muc.message(Candy.Util.escapeJid(roomJid), undefined, msg, type);
return true;
},
@@ -204,7 +200,7 @@ Candy.Core.Action = (function(self, Strophe, $) {
privacyList = currentUser.getPrivacyList('ignore');
if (privacyList.length > 0) {
$.each(privacyList, function(index, jid) {
- iq.c('item', {type:'jid', value: jid, action: 'deny', order : index})
+ iq.c('item', {type:'jid', value: Candy.Util.escapeJid(jid), action: 'deny', order : index})
.c('message').up().up();
});
} else {
@@ -231,7 +227,7 @@ Candy.Core.Action = (function(self, Strophe, $) {
*/
UserAction: function(roomJid, userJid, type, reason) {
var iqId,
- itemObj = {nick: Strophe.getResourceFromJid(userJid)};
+ itemObj = {nick: Strophe.escapeNode(Strophe.getResourceFromJid(userJid))};
switch(type) {
case 'kick':
iqId = 'kick1';
diff --git a/src/core/chatUser.js b/src/core/chatUser.js
index 8337388..58d083e 100644
--- a/src/core/chatUser.js
+++ b/src/core/chatUser.js
@@ -29,24 +29,42 @@ Candy.Core.ChatUser = function(jid, nick, affiliation, role) {
* - nick
* - affiliation
* - role
+ * - privacyLists
+ * - customData to be used by e.g. plugins
*/
this.data = {
jid: jid,
- nick: nick,
+ nick: Strophe.unescapeNode(nick),
affiliation: affiliation,
role: role,
privacyLists: {},
customData: {}
};
-
+
/** Function: getJid
- * Gets user jid
+ * Gets an unescaped user jid
+ *
+ * See:
+ * <Candy.Util.unescapeJid>
*
* Returns:
* (String) - jid
*/
this.getJid = function() {
- return this.data.jid;
+ return Candy.Util.unescapeJid(this.data.jid);
+ };
+
+ /** Function: getEscapedJid
+ * Escapes the user's jid (node & resource get escaped)
+ *
+ * See:
+ * <Candy.Util.escapeJid>
+ *
+ * Returns:
+ * (String) - escaped jid
+ */
+ this.getEscapedJid = function() {
+ return Candy.Util.escapeJid(this.data.jid);
};
/** Function: getNick
@@ -56,7 +74,7 @@ Candy.Core.ChatUser = function(jid, nick, affiliation, role) {
* (String) - nick
*/
this.getNick = function() {
- return this.data.nick;
+ return Strophe.unescapeNode(this.data.nick);
};
/** Function: getRole
diff --git a/src/core/event.js b/src/core/event.js
index b9ead2d..76c5f55 100644
--- a/src/core/event.js
+++ b/src/core/event.js
@@ -326,7 +326,7 @@ Candy.Core.Event = (function(self, Strophe, $, observable) {
*/
Presence: function(msg) {
Candy.Core.log('[Jabber:Room] Presence');
- var from = msg.attr('from'),
+ var from = Candy.Util.unescapeJid(msg.attr('from')),
roomJid = Strophe.getBareJidFromJid(from),
presenceType = msg.attr('type');
@@ -349,17 +349,18 @@ Candy.Core.Event = (function(self, Strophe, $, observable) {
Candy.Core.getRooms()[roomJid] = new Candy.Core.ChatRoom(roomJid);
room = Candy.Core.getRoom(roomJid);
}
- // Room existed but user was not registered
- if(room.getUser() === null) {
- room.setUser(Candy.Core.getUser());
- }
var roster = room.getRoster(),
action, user,
item = msg.find('item');
// User joined a room
if(presenceType !== 'unavailable') {
- user = new Candy.Core.ChatUser(from, Strophe.getResourceFromJid(from), item.attr('affiliation'), item.attr('role'));
+ var nick = Strophe.getResourceFromJid(from);
+ user = new Candy.Core.ChatUser(from, nick, item.attr('affiliation'), item.attr('role'));
+ // Room existed but client (myself) is not yet registered
+ if(room.getUser() === null && Candy.Core.getUser().getNick() === nick) {
+ room.setUser(user);
+ }
roster.add(user);
action = 'join';
// User left a room
@@ -395,29 +396,43 @@ Candy.Core.Event = (function(self, Strophe, $, observable) {
// Room subject
var roomJid, message;
if(msg.children('subject').length > 0) {
- roomJid = Strophe.getBareJidFromJid(msg.attr('from'));
+ roomJid = Candy.Util.unescapeJid(Strophe.getBareJidFromJid(msg.attr('from')));
message = { name: Strophe.getNodeFromJid(roomJid), body: msg.children('subject').text(), type: 'subject' };
// Error messsage
} else if(msg.attr('type') === 'error') {
var error = msg.children('error');
if(error.attr('code') === '500' && error.children('text').length > 0) {
roomJid = msg.attr('from');
- message = { type: 'error', body: error.children('text').text() };
+ message = { type: 'info', body: error.children('text').text() };
+ }
+ // Chat message
+ } else if(msg.children('body').length > 0) {
+ // Private chat message
+ if(msg.attr('type') === 'chat') {
+ roomJid = Candy.Util.unescapeJid(msg.attr('from'));
+ var bareRoomJid = Strophe.getBareJidFromJid(roomJid),
+ // if a 3rd-party client sends a direct message to this user (not via the room) then the username is the node and not the resource.
+ isNoConferenceRoomJid = !Candy.Core.getRoom(bareRoomJid),
+ name = isNoConferenceRoomJid ? Strophe.getNodeFromJid(roomJid) : Strophe.getResourceFromJid(roomJid);
+ message = { name: name, body: msg.children('body').text(), type: msg.attr('type'), isNoConferenceRoomJid: isNoConferenceRoomJid };
+ // Multi-user chat message
+ } else {
+ roomJid = Candy.Util.unescapeJid(Strophe.getBareJidFromJid(msg.attr('from')));
+ var resource = Strophe.getResourceFromJid(msg.attr('from'));
+ // Message from a user
+ if(resource) {
+ resource = Strophe.unescapeNode(resource);
+ message = { name: resource, body: msg.children('body').text(), type: msg.attr('type') };
+ // Message from server (XEP-0045#registrar-statuscodes)
+ } else {
+ message = { name: '', body: msg.children('body').text(), type: 'info' };
+ }
}
- // Private chat message
- } else if(msg.attr('type') === 'chat') {
- roomJid = msg.attr('from');
- var bareRoomJid = Strophe.getBareJidFromJid(roomJid),
- // if a 3rd-party client sends a direct message to this user (not via the room) then the username is the node and not the resource.
- isNoConferenceRoomJid = !Candy.Core.getRoom(bareRoomJid),
- name = isNoConferenceRoomJid ? Strophe.getNodeFromJid(roomJid) : Strophe.getResourceFromJid(roomJid);
- message = { name: name, body: msg.children('body').text(), type: msg.attr('type'), isNoConferenceRoomJid: isNoConferenceRoomJid };
- // Multi-user chat message
+ // Unhandled message
} else {
- roomJid = Strophe.getBareJidFromJid(msg.attr('from'));
- message = { name: Strophe.getResourceFromJid(msg.attr('from')), body: msg.children('body').text(), type: msg.attr('type') };
+ return true;
}
-
+
// besides the delayed delivery (XEP-0203), there exists also XEP-0091 which is the legacy delayed delivery.
// the x[xmlns=jabber:x:delay] is the format in XEP-0091.
var delay = msg.children('delay') ? msg.children('delay') : msg.children('x[xmlns="' + Strophe.NS.DELAY +'"]'),
diff --git a/src/util.js b/src/util.js
index 419a4af..e4b610a 100644
--- a/src/util.js
+++ b/src/util.js
@@ -29,6 +29,56 @@ Candy.Util = (function(self, $){
self.jidToId = function(jid) {
return MD5.hexdigest(jid);
};
+
+ /** Function: escapeJid
+ * Escapes a jid (node & resource get escaped)
+ *
+ * See:
+ * XEP-0106
+ *
+ * Parameters:
+ * (String) jid - Jid
+ *
+ * Returns:
+ * (String) - escaped jid
+ */
+ self.escapeJid = function(jid) {
+ var node = Strophe.escapeNode(Strophe.getNodeFromJid(jid)),
+ domain = Strophe.getDomainFromJid(jid),
+ resource = Strophe.getResourceFromJid(jid);
+
+ jid = node + '@' + domain;
+ if (resource) {
+ jid += '/' + Strophe.escapeNode(resource);
+ }
+
+ return jid;
+ };
+
+ /** Function: unescapeJid
+ * Unescapes a jid (node & resource get unescaped)
+ *
+ * See:
+ * XEP-0106
+ *
+ * Parameters:
+ * (String) jid - Jid
+ *
+ * Returns:
+ * (String) - unescaped Jid
+ */
+ self.unescapeJid = function(jid) {
+ var node = Strophe.unescapeNode(Strophe.getNodeFromJid(jid)),
+ domain = Strophe.getDomainFromJid(jid),
+ resource = Strophe.getResourceFromJid(jid);
+
+ jid = node + '@' + domain;
+ if(resource) {
+ jid += '/' + Strophe.unescapeNode(resource);
+ }
+
+ return jid;
+ };
/** Function: crop
* Crop a string with the specified length
@@ -55,7 +105,7 @@ Candy.Util = (function(self, $){
self.setCookie = function(name, value, lifetime_days) {
var exp = new Date();
exp.setDate(new Date().getDate() + lifetime_days);
- document.cookie = name + '=' + value + ';expires=' + exp.toUTCString() + 'path=/';
+ document.cookie = name + '=' + value + ';expires=' + exp.toUTCString() + ';path=/';
};
/** Function: cookieExists
diff --git a/src/view.js b/src/view.js
index 62eac25..94f1f69 100644
--- a/src/view.js
+++ b/src/view.js
@@ -112,7 +112,7 @@ Candy.View = (function(self, $) {
* (Object) options - Options: see _options field (value passed here gets extended by the default value in _options field)
*/
self.init = function(container, options) {
- $.extend(_options, options);
+ $.extend(true, _options, options);
_setupTranslation(_options.language);
// Set path to emoticons
diff --git a/src/view/event.js b/src/view/event.js
index 685f0d6..d7898e9 100644
--- a/src/view/event.js
+++ b/src/view/event.js
@@ -158,13 +158,13 @@ Candy.View.Event = (function(self, $) {
* Called before a new message will be shown.
*
* Parameters:
- * (String) message - parsed message
+ * (Object) args - {roomJid, nick, message}
*
* Returns:
* (String) message
*/
- beforeShow: function(message) {
- return message;
+ beforeShow: function(args) {
+ return args.message;
},
/** Function: onShow
diff --git a/src/view/observer.js b/src/view/observer.js
index 02f5971..f3a4a7e 100644
--- a/src/view/observer.js
+++ b/src/view/observer.js
@@ -37,7 +37,7 @@ Candy.View.Observer = (function(self, $) {
case Strophe.Status.AUTHENTICATING:
Candy.View.Pane.Chat.Modal.show($.i18n._('statusConnecting'), false, true);
break;
-
+
case Strophe.Status.ATTACHED:
case Strophe.Status.CONNECTED:
Candy.View.Pane.Chat.Modal.show($.i18n._('statusConnected'));
@@ -52,7 +52,7 @@ Candy.View.Observer = (function(self, $) {
Candy.View.Pane.Chat.Modal.showLoginForm($.i18n._('statusDisconnected'));
Candy.View.Event.Chat.onDisconnect();
break;
-
+
case Strophe.Status.AUTHFAIL:
Candy.View.Pane.Chat.Modal.showLoginForm($.i18n._('statusAuthfail'));
Candy.View.Event.Chat.onAuthfail();
@@ -130,7 +130,7 @@ Candy.View.Observer = (function(self, $) {
}
}
},
-
+
/** Function: notifyPrivateChats
* Notify private user chats if existing
*
@@ -163,8 +163,12 @@ Candy.View.Observer = (function(self, $) {
*/
update: function(obj, args) {
if(args.message.type === 'subject') {
+ if (!Candy.View.Pane.Chat.rooms[args.roomJid]) {
+ Candy.View.Pane.Room.init(args.roomJid, args.message.name);
+ Candy.View.Pane.Room.show(args.roomJid);
+ }
Candy.View.Pane.Room.setSubject(args.roomJid, args.message.body);
- } else if(args.message.type === 'error') {
+ } else if(args.message.type === 'info') {
Candy.View.Pane.Chat.infoMessage(args.roomJid, args.message.body);
} else {
// Initialize room if it's a message for a new private user chat
diff --git a/src/view/pane.js b/src/view/pane.js
index 799ea4a..5244dbe 100644
--- a/src/view/pane.js
+++ b/src/view/pane.js
@@ -561,8 +561,8 @@ Candy.View.Pane = (function(self, $) {
*/
hideCloseControl: function() {
$('#admin-message-cancel').hide().click(function() {});
- },
-
+ },
+
/** Function: showLoginForm
* Show the login form modal
*
@@ -574,23 +574,30 @@ Candy.View.Pane = (function(self, $) {
Candy.View.Pane.Chat.Modal.show((message ? message : '') + Mustache.to_html(Candy.View.Template.Login.form, {
_labelUsername: $.i18n._('labelUsername'),
_labelPassword: $.i18n._('labelPassword'),
- _loginSubmit : $.i18n._('loginSubmit'),
- presetJid : (presetJid ? presetJid : false)
+ _loginSubmit: $.i18n._('loginSubmit'),
+ displayPassword: !Candy.Core.isAnonymousConnection(),
+ displayUsername: Candy.Core.isAnonymousConnection() || !presetJid,
+ presetJid: presetJid ? presetJid : false
}));
// register submit handler
$('#login-form').submit(function(event) {
var username = $('#username').val(),
- password = $('#password').val(),
+ password = $('#password').val();
+
+ if (!Candy.Core.isAnonymousConnection()) {
// guess the input and create a jid out of it
- jid = Candy.Core.getUser() && username.indexOf("@") < 0 ?
+ var jid = Candy.Core.getUser() && username.indexOf("@") < 0 ?
username + '@' + Strophe.getDomainFromJid(Candy.Core.getUser().getJid()) : username;
-
- if(jid.indexOf("@") < 0 && !Candy.Core.getUser()) {
- Candy.View.Pane.Chat.Modal.showLoginForm($.i18n._('loginInvalid'));
- } else {
- //Candy.View.Pane.Chat.Modal.hide();
- Candy.Core.connect(jid, password);
+
+ if(jid.indexOf("@") < 0 && !Candy.Core.getUser()) {
+ Candy.View.Pane.Chat.Modal.showLoginForm($.i18n._('loginInvalid'));
+ } else {
+ //Candy.View.Pane.Chat.Modal.hide();
+ Candy.Core.connect(jid, password);
+ }
+ } else { // anonymous login
+ Candy.Core.connect(presetJid, null, username);
}
return false;
});
@@ -929,8 +936,7 @@ Candy.View.Pane = (function(self, $) {
roomJid: roomJid,
roomType: roomType,
form: {
- _messageSubmit: $.i18n._('messageSubmit'),
- _maxLength: Candy.View.getOptions().crop.message.body
+ _messageSubmit: $.i18n._('messageSubmit')
},
roster: {
_userOnline: $.i18n._('userOnline')
@@ -1337,7 +1343,7 @@ Candy.View.Pane = (function(self, $) {
userId : userId,
userJid: user.getJid(),
nick: user.getNick(),
- displayNick: Candy.Util.crop(user.getNick(), Candy.View.getOptions().crop.roster.nickname),
+ displayNick: Candy.Util.crop(user.getNick(), Candy.View.getOptions().crop.roster.displayNick),
role: user.getRole(),
affiliation: user.getAffiliation(),
me: currentUser !== undefined && user.getNick() === currentUser.getNick(),
@@ -1380,6 +1386,7 @@ Candy.View.Pane = (function(self, $) {
}
// user is in room but maybe the affiliation/role has changed
} else {
+ usercountDiff = 0;
userElem.replaceWith(html);
$('#user-' + roomId + '-' + userId).css({opacity: 1}).show();
}
@@ -1477,7 +1484,7 @@ Candy.View.Pane = (function(self, $) {
*/
submit: function(event) {
var roomType = Candy.View.Pane.Chat.rooms[Candy.View.getCurrent().roomJid].type,
- message = $(this).children('.field').val().substring(0, Candy.View.getOptions().crop.message.body);
+ message = $(this).children('.field').val().substring(0, 1000);
message = Candy.View.Event.Message.beforeSend(message);
@@ -1501,11 +1508,15 @@ Candy.View.Pane = (function(self, $) {
* (String) timestamp - [optional] Timestamp of the message, if not present, current date.
*/
show: function(roomJid, name, message, timestamp) {
- message = Candy.Util.Parser.all(message.substring(0, Candy.View.getOptions().crop.message.body));
- message = Candy.View.Event.Message.beforeShow(message);
+ message = Candy.Util.Parser.all(message.substring(0, 1000));
+ message = Candy.View.Event.Message.beforeShow({'roomJid': roomJid, 'nick': name, 'message': message});
+ if(!message) {
+ return;
+ }
+
var html = Mustache.to_html(Candy.View.Template.Message.item, {
name: name,
- displayName: Candy.Util.crop(name, Candy.View.getOptions().crop.message.nickname),
+ displayName: Candy.Util.crop(name, Candy.View.getOptions().crop.message.displayName),
message: message,
time: Candy.Util.localizedTime(timestamp || new Date().toGMTString())
});
diff --git a/src/view/template.js b/src/view/template.js
index 9ca5f42..f231519 100644
--- a/src/view/template.js
+++ b/src/view/template.js
@@ -46,7 +46,7 @@ Candy.View.Template = (function(self){
self.Room = {
pane: '<div class="room-pane roomtype-{{roomType}}" id="chat-room-{{roomId}}" data-roomjid="{{roomJid}}" data-roomtype="{{roomType}}">{{> roster}}{{> messages}}{{> form}}</div>',
subject: '<dt>{{time}}</dt><dd class="subject"><span class="label">{{roomName}}</span>{{_roomSubject}} {{subject}}</dd>',
- form: '<div class="message-form-wrapper"></div><form method="post" class="message-form"><input name="message" class="field" type="text" autocomplete="off" maxlength="{{_maxLength}}" /><input type="submit" class="submit" name="submit" value="{{_messageSubmit}}" /></form>'
+ form: '<div class="message-form-wrapper"></div><form method="post" class="message-form"><input name="message" class="field" type="text" autocomplete="off" maxlength="1000" /><input type="submit" class="submit" name="submit" value="{{_messageSubmit}}" /></form>'
};
self.Roster = {
@@ -61,9 +61,9 @@ Candy.View.Template = (function(self){
self.Login = {
form: '<form method="post" id="login-form" class="login-form">'
- + '{{^presetJid}}<label for="username">{{_labelUsername}}</label><input type="text" id="username" name="username"/>{{/presetJid}}'
+ + '{{#displayUsername}}<label for="username">{{_labelUsername}}</label><input type="text" id="username" name="username"/>{{/displayUsername}}'
+ '{{#presetJid}}<input type="hidden" id="username" name="username" value="{{presetJid}}"/>{{/presetJid}}'
- + '<label for="password">{{_labelPassword}}</label><input type="password" id="password" name="password" />'
+ + '{{#displayPassword}}<label for="password">{{_labelPassword}}</label><input type="password" id="password" name="password" />{{/displayPassword}}'
+ '<input type="submit" class="button" value="{{_loginSubmit}}" /></form>'
};