';
+
// Show the close button if not MUC and not anonymous
- if(show_close)
- html += '
x
';
-
+ if(show_close) {
+ html += '
' +
+ 'x' +
+ '
';
+ }
+
// Close the HTML
html += '
';
-
+
// Append the HTML code
$(chat_switch + 'chans, ' + chat_switch + 'more-content').append(html);
} catch(e) {
@@ -295,10 +519,10 @@ var Chat = (function () {
try {
// Remove the messages
$('#page-engine #' + chat + ' .content .one-group').remove();
-
+
// Clear the history database
Message.removeLocalArchive(chat);
-
+
// Focus again
$(document).oneTime(10, function() {
$('#page-engine #' + chat + ' .text .message-area').focus();
@@ -346,14 +570,14 @@ var Chat = (function () {
try {
Console.info('New chat: ' + xid);
-
+
// Create the chat content
self.generate(type, hash, xid, nick);
-
+
// Create the chat switcher
self.generateSwitch(type, hash, xid, nick);
-
- // If the user is not in our roster
+
+ // Is this a chat?
if(type == 'chat') {
// MAM? Get archives from there!
if(Features.enabledMAM()) {
@@ -366,130 +590,73 @@ var Chat = (function () {
} else {
// Restore the chat history
var chat_history = Message.readLocalArchive(hash);
-
+
if(chat_history) {
// Generate hashs
var my_hash = hex_md5(Common.getXID());
var friend_hash = hex_md5(xid);
-
+
// Add chat history HTML
- $('#' + hash + ' .content').append(chat_history);
-
+ var path_sel = $('#' + hash);
+
+ path_sel.find('.content').append(chat_history);
+
// Filter old groups & messages
- $('#' + hash + ' .one-group[data-type="user-message"]').addClass('from-history').attr('data-type', 'old-message');
- $('#' + hash + ' .user-message').removeClass('user-message').addClass('old-message');
-
+ var one_group_sel = path_sel.find('.one-group');
+ one_group_sel.filter('[data-type="user-message"]').addClass('from-history').attr('data-type', 'old-message');
+ path_sel.find('.user-message').removeClass('user-message').addClass('old-message');
+
// Regenerate user names
- $('#' + hash + ' .one-group.' + my_hash + ' b.name').text(Name.getBuddy(Common.getXID()));
- $('#' + hash + ' .one-group.' + friend_hash + ' b.name').text(Name.getBuddy(xid));
-
+ one_group_sel.filter('.' + my_hash + ' b.name').text(
+ Name.getBuddy(Common.getXID())
+ );
+
+ one_group_sel.filter('.' + friend_hash + ' b.name').text(
+ Name.getBuddy(xid)
+ );
+
// Regenerate group dates
- $('#' + hash + ' .one-group').each(function() {
- var current_stamp = parseInt($(this).attr('data-stamp'));
+ one_group_sel.each(function() {
+ var current_stamp = parseInt($(this).attr('data-stamp'), 10);
$(this).find('span.date').text(DateUtils.relative(current_stamp));
});
-
+
// Regenerate avatars
- if(Common.exists('#' + hash + ' .one-group.' + my_hash + ' .avatar-container'))
+ if(Common.exists('#' + hash + ' .one-group.' + my_hash + ' .avatar-container')) {
Avatar.get(Common.getXID(), 'cache', 'true', 'forget');
- if(Common.exists('#' + hash + ' .one-group.' + friend_hash + ' .avatar-container'))
+ }
+
+ if(Common.exists('#' + hash + ' .one-group.' + friend_hash + ' .avatar-container')) {
Avatar.get(xid, 'cache', 'true', 'forget');
+ }
}
}
// Add button
- if(!Roster.isFriend(xid))
+ if(!Roster.isFriend(xid)) {
$('#' + hash + ' .tools-add').click(function() {
// Hide the icon (to tell the user all is okay)
$(this).hide();
-
+
// Send the subscribe request
Roster.addThisContact(xid, nick);
}).show();
+ }
}
-
+
// We catch the user's informations (like this avatar, vcard, and so on...)
UserInfos.get(hash, xid, nick, type);
-
+
// The icons-hover functions
Tooltip.icons(xid, hash);
-
+
// The event handlers
- var inputDetect = $('#page-engine #' + hash + ' .message-area');
-
- inputDetect.focus(function() {
- // Clean notifications for this chat
- Interface.chanCleanNotify(hash);
-
- // Store focus on this chat!
- Interface.chat_focus_hash = hash;
- });
-
- inputDetect.blur(function() {
- // Reset storage about focus on this chat!
- if(Interface.chat_focus_hash == hash)
- Interface.chat_focus_hash = null;
- });
-
- inputDetect.keypress(function(e) {
- // Enter key
- if(e.keyCode == 13) {
- // Add a new line
- if(e.shiftKey || e.ctrlKey) {
- inputDetect.val(inputDetect.val() + '\n');
- } else {
- // Send the message
- Message.send(hash, 'chat');
-
- // Reset the composing database entry
- DataStore.setDB(Connection.desktop_hash, 'chatstate', xid, 'off');
- }
-
- return false;
- }
- });
+ var input_sel = $('#page-engine #' + hash + ' .message-area');
+ self._createEvents(input_sel, xid, hash);
- // Scroll in chat content
- $('#page-engine #' + hash + ' .content').scroll(function() {
- var self = this;
-
- if(Features.enabledMAM() && !(xid in MAM.map_pending)) {
- var has_state = xid in MAM.map_states;
- var rsm_count = has_state ? MAM.map_states[xid].rsm.count : 1;
- var rsm_before = has_state ? MAM.map_states[xid].rsm.first : '';
-
- // Request more archives?
- if(rsm_count > 0 && $(this).scrollTop() < MAM.SCROLL_THRESHOLD) {
- var was_scroll_top = $(self).scrollTop() <= 32;
- var wait_mam = $('#' + hash).find('.wait-mam');
- wait_mam.show();
-
- MAM.getArchives({
- 'with': xid
- }, {
- 'max': MAM.REQ_MAX,
- 'before': rsm_before
- }, function() {
- var wait_mam_height = was_scroll_top ? 0 : wait_mam.height();
- wait_mam.hide();
-
- // Restore scroll?
- if($(self).scrollTop() < MAM.SCROLL_THRESHOLD) {
- var sel_mam_chunk = $(self).find('.mam-chunk:first');
-
- var cont_padding_top = parseInt($(self).css('padding-top').replace(/[^-\d\.]/g, ''));
- var cont_one_group_margin_bottom = parseInt(sel_mam_chunk.find('.one-group:last').css('margin-bottom').replace(/[^-\d\.]/g, ''));
- var cont_mam_chunk_height = sel_mam_chunk.height();
-
- $(self).scrollTop(wait_mam_height + cont_padding_top + cont_one_group_margin_bottom + cont_mam_chunk_height);
- }
- });
- }
- }
- });
-
- // Chatstate events
- ChatState.events(inputDetect, xid, hash, 'chat');
+ // Input events
+ ChatState.events(input_sel, xid, hash, 'chat');
+ Markers.events(input_sel, xid, hash, 'chat');
} catch(e) {
Console.error('Chat.create', e);
}
@@ -502,4 +669,4 @@ var Chat = (function () {
*/
return self;
-})();
\ No newline at end of file
+})();
diff --git a/source/app/javascripts/chatstate.js b/source/app/javascripts/chatstate.js
index ad55101..d0353fb 100644
--- a/source/app/javascripts/chatstate.js
+++ b/source/app/javascripts/chatstate.js
@@ -32,24 +32,27 @@ var ChatState = (function () {
try {
var user_type = $('#' + hash).attr('data-type');
-
+
// If the friend client supports chatstates and is online
if((user_type == 'groupchat') || ((user_type == 'chat') && $('#' + hash + ' .message-area').attr('data-chatstates') && !Common.exists('#page-switch .' + hash + ' .unavailable'))) {
// Already sent?
- if(DataStore.getDB(Connection.desktop_hash, 'currentchatstate', xid) == state)
+ if(DataStore.getDB(Connection.desktop_hash, 'currentchatstate', xid) == state) {
return;
-
+ }
+
// Write the state
DataStore.setDB(Connection.desktop_hash, 'currentchatstate', xid, state);
-
+
// New message stanza
var aMsg = new JSJaCMessage();
aMsg.setTo(xid);
aMsg.setType(user_type);
-
+
// Append the chatstate node
- aMsg.appendNode(state, {'xmlns': NS_CHATSTATES});
-
+ aMsg.appendNode(state, {
+ 'xmlns': NS_CHATSTATES
+ });
+
// Send this!
con.send(aMsg);
}
@@ -74,58 +77,61 @@ var ChatState = (function () {
// Groupchat?
if(type == 'groupchat') {
self.reset(hash, type);
-
+
// "gone" state not allowed
- if(state != 'gone')
+ if(state != 'gone') {
$('#page-engine .page-engine-chan .user.' + hash).addClass(state);
+ }
}
-
+
// Chat
else {
// We change the buddy name color in the page-switch
self.reset(hash, type);
$('#page-switch .' + hash + ' .name').addClass(state);
-
+
// We generate the chatstate text
var text = '';
-
+
switch(state) {
// Active
case 'active':
text = Common._e("Your friend is paying attention to the conversation.");
-
+
break;
-
+
// Composing
case 'composing':
text = Common._e("Your friend is writing a message...");
-
+
break;
-
+
// Paused
case 'paused':
text = Common._e("Your friend stopped writing a message.");
-
+
break;
-
+
// Inactive
case 'inactive':
text = Common._e("Your friend is doing something else.");
-
+
break;
-
+
// Gone
case 'gone':
text = Common._e("Your friend closed the chat.");
-
+
break;
}
-
+
// We reset the previous state
$('#' + hash + ' .chatstate').remove();
-
+
// We create the chatstate
- $('#' + hash + ' .content').after('
' + text + '
');
+ $('#' + hash + ' .content').after(
+ '
' + text + '
'
+ );
}
} catch(e) {
Console.error('ChatState.display', e);
@@ -146,12 +152,13 @@ var ChatState = (function () {
try {
// Define the selector
var selector;
-
- if(type == 'groupchat')
+
+ if(type == 'groupchat') {
selector = $('#page-engine .page-engine-chan .user.' + hash);
- else
+ } else {
selector = $('#page-switch .' + hash + ' .name');
-
+ }
+
// Reset!
selector.removeClass('active composing paused inactive gone');
} catch(e) {
@@ -179,53 +186,56 @@ var ChatState = (function () {
if($(this).val() && (DataStore.getDB(Connection.desktop_hash, 'chatstate', xid) != 'on')) {
// We change the state detect input
DataStore.setDB(Connection.desktop_hash, 'chatstate', xid, 'on');
-
+
// We send the friend a "composing" chatstate
self.send('composing', xid, hash);
}
-
+
// Flushed the message which was being composed
else if(!$(this).val() && (DataStore.getDB(Connection.desktop_hash, 'chatstate', xid) == 'on')) {
// We change the state detect input
DataStore.setDB(Connection.desktop_hash, 'chatstate', xid, 'off');
-
+
// We send the friend an "active" chatstate
self.send('active', xid, hash);
}
}
});
-
+
target.change(function() {
// Reset the composing database entry
DataStore.setDB(Connection.desktop_hash, 'chatstate', xid, 'off');
});
-
+
target.focus(function() {
// Not needed
- if(target.is(':disabled'))
+ if(target.is(':disabled')) {
return;
-
+ }
+
// Something was written, user started writing again
- if($(this).val())
+ if($(this).val()) {
self.send('composing', xid, hash);
+ }
// Chat only: Nothing in the input, user is active
- else if(type == 'chat')
+ else if(type == 'chat') {
self.send('active', xid, hash);
+ }
});
-
+
target.blur(function() {
// Not needed
- if(target.is(':disabled'))
+ if(target.is(':disabled')) {
return;
-
- // Something was written, user paused
- if($(this).val())
- self.send('paused', xid, hash);
+ }
- // Chat only: Nothing in the input, user is inactive
- else if(type == 'chat')
+ // Something was written, user paused
+ if($(this).val()) {
+ self.send('paused', xid, hash);
+ } else if(type == 'chat') {
self.send('inactive', xid, hash);
+ }
});
} catch(e) {
Console.error('ChatState.events', e);
diff --git a/source/app/javascripts/common.js b/source/app/javascripts/common.js
index c6047a9..5874604 100644
--- a/source/app/javascripts/common.js
+++ b/source/app/javascripts/common.js
@@ -20,6 +20,10 @@ var Common = (function () {
var self = {};
+ /* Constants */
+ self.R_DOMAIN_NAME = /^(([a-zA-Z0-9-\.]+)\.)?[a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9]\.[a-zA-Z]{2,}$/i;
+
+
/**
* Checks if an element exists in the DOM
* @public
@@ -109,6 +113,29 @@ var Common = (function () {
};
+ /**
+ * Matches a domain name
+ * @public
+ * @param {string} xid
+ * @return {boolean}
+ */
+ self.isDomain = function(xid) {
+
+ is_domain = false;
+
+ try {
+ if(xid.match(self.R_DOMAIN_NAME)) {
+ is_domain = true;
+ }
+ } catch(e) {
+ Console.error('Common.isDomain', e);
+ } finally {
+ return is_domain;
+ }
+
+ };
+
+
/**
* Generates the good XID
* @public
@@ -120,22 +147,23 @@ var Common = (function () {
try {
// XID needs to be transformed
- // .. and made lowercase (uncertain though this is the right place...)
xid = xid.toLowerCase();
- if(xid && (xid.indexOf('@') == -1)) {
- // Groupchat
- if(type == 'groupchat')
+ if(xid && (xid.indexOf('@') === -1)) {
+ // Groupchat XID
+ if(type == 'groupchat') {
return xid + '@' + HOST_MUC;
-
- // One-to-one chat
- if(xid.indexOf('.') == -1)
- return xid + '@' + HOST_MAIN;
-
- // It might be a gateway?
- return xid;
+ }
+
+ // Gateway XID
+ if(self.isDomain(xid) === true) {
+ return xid;
+ }
+
+ // User XID
+ return xid + '@' + HOST_MAIN;
}
-
+
// Nothing special (yet bare XID)
return xid;
} catch(e) {
@@ -190,15 +218,17 @@ var Common = (function () {
self.strAfterLast = function(given_char, str) {
try {
- if(!given_char || !str)
+ if(!given_char || !str) {
return '';
-
+ }
+
var char_index = str.lastIndexOf(given_char);
var str_return = str;
-
- if(char_index >= 0)
+
+ if(char_index >= 0) {
str_return = str.substr(char_index + 1);
-
+ }
+
return str_return;
} catch(e) {
Console.error('Common.strAfterLast', e);
@@ -220,15 +250,16 @@ var Common = (function () {
try {
// Get the index of our char to explode
var index = toStr.indexOf(toEx);
-
+
// We split if necessary the string
if(index !== -1) {
- if(i === 0)
+ if(i === 0) {
toStr = toStr.substr(0, index);
- else
+ } else {
toStr = toStr.substr(index + 1);
+ }
}
-
+
// We return the value
return toStr;
} catch(e) {
@@ -309,8 +340,9 @@ var Common = (function () {
// Spec: http://tools.ietf.org/html/rfc6122#appendix-A
try {
- if(!node)
+ if(!node) {
return node;
+ }
// Remove prohibited chars
var prohibited_chars = ['"', '&', '\'', '/', ':', '<', '>', '@'];
@@ -347,6 +379,40 @@ var Common = (function () {
};
+ /**
+ * Escapes quotes in a string
+ * @public
+ * @param {string} str
+ * @return {string}
+ */
+ self.escapeQuotes = function(str) {
+
+ try {
+ return escape(self.encodeQuotes(str));
+ } catch(e) {
+ Console.error('Common.escapeQuotes', e);
+ }
+
+ };
+
+
+ /**
+ * Unescapes quotes in a string
+ * @public
+ * @param {string} str
+ * @return {string}
+ */
+ self.unescapeQuotes = function(str) {
+
+ try {
+ return unescape(str);
+ } catch(e) {
+ Console.error('Common.unescapeQuotes', e);
+ }
+
+ };
+
+
/**
* Gets the bare XID from a XID
* @public
@@ -358,12 +424,12 @@ var Common = (function () {
try {
// Cut the resource
xid = self.cutResource(xid);
-
+
// Launch nodeprep
- if(xid.indexOf('@') != -1) {
- xid = self.nodeprep(self.getXIDNick(xid)) + '@' + self.getXIDHost(xid);
+ if(xid.indexOf('@') !== -1) {
+ xid = self.nodeprep(self.getXIDNick(xid, true)) + '@' + self.getXIDHost(xid);
}
-
+
return xid;
} catch(e) {
Console.error('Common.bareXID', e);
@@ -384,11 +450,12 @@ var Common = (function () {
// Normalizes the XID
var full = self.bareXID(xid);
var resource = self.thisResource(xid);
-
+
// Any resource?
- if(resource)
+ if(resource) {
full += '/' + resource;
-
+ }
+
return full;
} catch(e) {
Console.error('Common.fullXID', e);
@@ -401,15 +468,19 @@ var Common = (function () {
* Gets the nick from a XID
* @public
* @param {string} aXID
+ * @param {boolean} raw_explode
* @return {string}
*/
- self.getXIDNick = function(aXID) {
+ self.getXIDNick = function(aXID, raw_explode) {
try {
- // Gateway nick?
- if(aXID.match(/\\40/))
- return self.explodeThis('\\40', aXID, 0);
-
+ if(raw_explode !== true) {
+ // Gateway nick?
+ if(aXID.match(/\\40/)) {
+ return self.explodeThis('\\40', aXID, 0);
+ }
+ }
+
return self.explodeThis('@', aXID, 0);
} catch(e) {
Console.error('Common.getXIDNick', e);
@@ -484,7 +555,7 @@ var Common = (function () {
/**
- * Gets the full XID of the user
+ * Gets the bare XID of the user
* @public
* @return {string}
*/
@@ -495,7 +566,7 @@ var Common = (function () {
if(con.username && con.domain) {
return con.username + '@' + con.domain;
}
-
+
return '';
} catch(e) {
Console.error('Common.getXID', e);
@@ -504,6 +575,29 @@ var Common = (function () {
};
+ /**
+ * Gets the full XID of the user
+ * @public
+ * @return {string}
+ */
+ self.getFullXID = function() {
+
+ try {
+ var xid = self.getXID();
+
+ // Return the full XID of the user
+ if(xid) {
+ return xid + '/' + con.resource;
+ }
+
+ return '';
+ } catch(e) {
+ Console.error('Common.getFullXID', e);
+ }
+
+ };
+
+
/**
* Generates the colors for a given user XID
* @public
@@ -521,15 +615,15 @@ var Common = (function () {
'00236b',
'4e005c'
);
-
+
var number = 0;
-
+
for(var i = 0; i < xid.length; i++) {
number += xid.charCodeAt(i);
}
-
+
var color = '#' + colors[number % (colors.length)];
-
+
return color;
} catch(e) {
Console.error('Common.generateColor', e);
@@ -549,7 +643,7 @@ var Common = (function () {
is_gateway = true;
try {
- if(xid.indexOf('@') != -1) {
+ if(xid.indexOf('@') !== -1) {
is_gateway = false;
}
} catch(e) {
@@ -571,12 +665,12 @@ var Common = (function () {
try {
var from = stanza.getFrom();
-
+
// No from, we assume this is our XID
if(!from) {
from = self.getXID();
}
-
+
return from;
} catch(e) {
Console.error('Common.getStanzaFrom', e);
@@ -618,13 +712,15 @@ var Common = (function () {
try {
// Negative number (without first 0)
- if(i > -10 && i < 0)
+ if(i > -10 && i < 0) {
return '-0' + (i * -1);
-
+ }
+
// Positive number (without first 0)
- if(i < 10 && i >= 0)
+ if(i < 10 && i >= 0) {
return '0' + i;
-
+ }
+
// All is okay
return i;
} catch(e) {
@@ -643,23 +739,31 @@ var Common = (function () {
*/
self.escapeRegex = function(query) {
- if (query instanceof Array) {
- var result = new Array(query.length);
- for(i=0; i' +
- Common._e("You have been registered, here is your XMPP address:") + ' ' + username.htmlEnc() + '@' + domain.htmlEnc() + ' - ' + Common._e("Login") + '' +
+ '
' +
+ Common._e("You have been registered, here is your XMPP address:") +
+ ' ' + username.htmlEnc() + '@' + domain.htmlEnc() + ' - ' +
+ '' + Common._e("Login") + '' +
'
'
);
-
+
// Login link
$('#home .homediv.registerer .success a').click(function() {
return self.doLogin(username, domain, pass, '', '10', false);
});
-
+
if((REGISTER_API == 'on') && (domain == HOST_MAIN) && captcha) {
- // Show the waiting image
- Interface.showGeneralWait();
-
- // Change the page title
- Interface.title('wait');
-
- // Send request
- $.post('./server/register.php', {username: username, domain: domain, password: pass, captcha: captcha}, function(data) {
- // Error registering
- Interface.removeGeneralWait();
- Interface.title('home');
-
- // In all case, update CAPTCHA
- $('#home img.captcha_img').attr('src', './server/captcha.php?id=' + genID());
- $('#home input.captcha').val('');
-
- // Registration okay
- if($(data).find('query status').text() == '1') {
- self.handleRegistered();
- } else {
- // Show error message
- var error_message = '';
-
- switch($(data).find('query message').text()) {
- case 'CAPTCHA Not Matching':
- error_message = Common._e("The security code you entered is invalid. Please retry with another one.");
-
- $('#home input.captcha').focus();
-
- break;
-
- case 'Username Unavailable':
- error_message = Common._e("The username you picked is not available. Please try another one.");
-
- $('#home input.nick').focus();
-
- break;
-
- default:
- error_message = Common._e("There was an error registering your account. Please retry.");
-
- break;
- }
-
- if(error_message)
- Errors.show('', error_message, '');
- }
- });
+ self._doRegisterAPI(username, domain, pass, captcha);
} else {
- try {
- oArgs = {};
-
- if(Common.hasWebSocket()) {
- // WebSocket supported & configured
- con = new JSJaCWebSocketConnection({
- httpbase: HOST_WEBSOCKET
- });
- } else {
- var httpbase = (HOST_BOSH_MAIN || HOST_BOSH);
-
- // Check BOSH origin
- BOSH_SAME_ORIGIN = Origin.isSame(httpbase);
-
- // We create the new http-binding connection
- con = new JSJaCHttpBindingConnection({
- httpbase: httpbase
- });
- }
-
- // We setup the connection !
- con.registerHandler('onconnect', self.handleRegistered);
- con.registerHandler('onerror', Errors.handle);
-
- // We retrieve what the user typed in the register inputs
- oArgs = {};
- oArgs.domain = $.trim(domain);
- oArgs.username = $.trim(username);
- oArgs.resource = JAPPIX_RESOURCE + ' Register (' + (new Date()).getTime() + ')';
- oArgs.pass = pass;
- oArgs.register = true;
- oArgs.secure = true;
- oArgs.xmllang = XML_LANG;
-
- con.connect(oArgs);
-
- // Show the waiting image
- Interface.showGeneralWait();
-
- // Change the page title
- Interface.title('wait');
- }
-
- catch(e) {
- // Logs errors
- Console.error('doRegister', e);
- }
+ self._doRegisterInBand(username, domain, pass);
}
} catch(e) {
Console.error('Connection.doRegister', e);
@@ -294,31 +402,29 @@ var Connection = (function () {
try {
Console.info('Trying to login anonymously...');
-
- var aPath = '#home .anonymouser ';
- var room = $(aPath + '.room').val();
- var nick = $(aPath + '.nick').val();
-
- // If the form is correctly completed
+
+ var path_sel = $('#home .anonymouser');
+ var room = path_sel.find('.room').val();
+ var nick = path_sel.find('.nick').val();
+
+ // Form correctly completed?
if(room && nick) {
// We remove the not completed class to avoid problems
$('#home .anonymouser input').removeClass('please-complete');
-
+
// Redirect the user to the anonymous room
window.location.href = JAPPIX_LOCATION + '?r=' + room + '&n=' + nick;
- }
-
- // We check if the form is entirely completed
- else {
- $(aPath + 'input[type="text"]').each(function() {
- var select = $(this);
-
- if(!select.val())
+ } else {
+ path_sel.find('input[type="text"]').each(function() {
+ var this_sel = $(this);
+
+ if(!this_sel.val()) {
$(document).oneTime(10, function() {
- select.addClass('please-complete').focus();
+ this_sel.addClass('please-complete').focus();
});
- else
- select.removeClass('please-complete');
+ } else {
+ this_sel.removeClass('please-complete');
+ }
});
}
} catch(e) {
@@ -339,23 +445,23 @@ var Connection = (function () {
try {
Console.info('Jappix is now connected.');
-
+
// Connection markers
self.connected = true;
self.reconnect_try = 0;
self.reconnect_timer = 0;
-
+
// We hide the home page
$('#home').hide();
-
+
// Any suggest to do before triggering connected event?
Groupchat.suggestCheck();
-
+
// Remove the waiting item
Interface.removeGeneralWait();
- // Init Jingle
- Jingle.init();
+ // Init call
+ Call.init();
} catch(e) {
Console.error('Connection.handleConnected', e);
}
@@ -374,27 +480,28 @@ var Connection = (function () {
// Not resumed?
if(!self.resume) {
// Remember the session?
- if(DataStore.getDB(self.desktop_hash, 'remember', 'session'))
+ if(DataStore.getDB(self.desktop_hash, 'remember', 'session')) {
DataStore.setPersistent('global', 'session', 1, self.current_session);
-
+ }
+
// We show the chatting app.
Talk.create();
-
+
// We reset the homepage
Home.change('default');
-
+
// We get all the other things
self.getEverything();
-
+
// Set last activity stamp
DateUtils.last_activity = DateUtils.getTimeStamp();
}
-
+
// Resumed
else {
// Send our presence
Presence.sendActions();
-
+
// Change the title
Interface.updateTitle();
}
@@ -414,7 +521,10 @@ var Connection = (function () {
try {
Console.info('Jappix is now disconnected.');
-
+
+ // Abort ongoing call (if any)
+ Call.stop(true);
+
// Normal disconnection
if(!self.current_session && !self.connected) {
Talk.destroy();
@@ -431,24 +541,32 @@ var Connection = (function () {
* Setups the normal connection
* @public
* @param {object} con
- * @param {object} oExtend
+ * @param {object} extend_obj
* @return {undefined}
*/
- self.setupCon = function(con, oExtend) {
+ self.setupCon = function(con, extend_obj) {
try {
- // Setup connection handlers
- con.registerHandler('message', Message.handle);
- con.registerHandler('presence', Presence.handle);
- con.registerHandler('iq', IQ.handle);
- con.registerHandler('onconnect', self.handleConnected);
- con.registerHandler('onerror', Errors.handle);
- con.registerHandler('ondisconnect', self.handleDisconnected);
-
+ var connection_handlers = {
+ 'message': Message.handle,
+ 'presence': Presence.handle,
+ 'iq': IQ.handle,
+ 'onconnect': self.handleConnected,
+ 'onerror': Errors.handle,
+ 'ondisconnect': self.handleDisconnected
+ };
+
+ for(var cur_handler in connection_handlers) {
+ con.registerHandler(
+ cur_handler,
+ connection_handlers[cur_handler]
+ );
+ }
+
// Extended handlers
- oExtend = oExtend || {};
-
- jQuery.each(oExtend, function(keywd,funct) {
+ extend_obj = extend_obj || {};
+
+ jQuery.each(extend_obj, function(keywd,funct) {
con.registerHandler(keywd, funct);
});
} catch(e) {
@@ -496,13 +614,13 @@ var Connection = (function () {
if(Common.isConnected()) {
// Clear temporary session storage
self.resetConMarkers();
-
+
// Show the waiting item (useful if BOSH is sloooow)
Interface.showGeneralWait();
-
+
// Change the page title
Interface.title('wait');
-
+
// Disconnect from the XMPP server
self.logout();
}
@@ -525,13 +643,13 @@ var Connection = (function () {
if(!Common.isConnected()) {
return;
}
-
+
// We show the waiting image
Interface.showGeneralWait();
-
+
// Change the page title
Interface.title('wait');
-
+
// We disconnect from the XMPP server
self.logout();
} catch(e) {
@@ -551,60 +669,34 @@ var Connection = (function () {
try {
Console.error('This is not a normal disconnection, show the reconnect pane...');
-
+
// Reconnect pane not yet displayed?
if(!Common.exists('#reconnect')) {
// Blur the focused input/textarea/select
$('input, select, textarea').blur();
-
+
// Create the HTML code
- var html = '
' +
- '
' +
- Common._e("Due to a network issue, you were disconnected. What do you want to do now?");
-
+ var html = '
' +
+ '
' +
+ Common._e("Due to a network issue, you were disconnected. What do you want to do now?");
+
// Can we cancel reconnection?
- if(mode == 'normal')
+ if(mode == 'normal') {
html += '' + Common._e("Cancel") + '';
-
- html += '' + Common._e("Reconnect") + '' +
- '
'
- );
-
- // Item with children
- else {
- // We display the waiting element
- $(pathID + ' .disco-wait .disco-category-title').after(
- '
' +
- '' +
- '
' + itemHost + '
' +
- '
' + Common._e("Requesting this service...") + '
' +
- '
'
- );
-
- // We display the category
- $('#' + target + ' .disco-wait').show();
-
- // We ask the server what's the service type
- self.getType(itemHost, itemNode, sessionID);
- }
- });
- }
-
- // Else, there are no items for this query
- else
- self.noResult(pathID);
- }
-
- else if((type == 'muc') || (type == 'search') || (type == 'subscribe') || ((type == 'command') && $(handleXML).find('command').attr('xmlns'))) {
- // Get some values
- var xCommand = $(handleXML).find('command');
- var bNode = xCommand.attr('node');
- var bSession = xCommand.attr('sessionid');
- var bStatus = xCommand.attr('status');
- var xRegister = $(handleXML).find('query[xmlns="' + NS_REGISTER + '"]').text();
- var xElement = $(handleXML).find('x');
-
- // Search done
- if((xElement.attr('type') == 'result') && (type == 'search')) {
- var bPath = pathID;
-
- // Display the result
- $(handleXML).find('item').each(function() {
- // Have some "flexibility" for what regards field names, it would be better to return the whole original DF
- // layout, but on a large amount of result which have many fields, there's a very high chance the browser can
- // choke on old systems or new ones even.
-
- // Search for useful fields, return first result. This is rather hacky, but jQuery is horrible when it comes to
- // matching st. using patterns. (TODO: Improve and return the full DF layout without choking the browser)
- var bName;
- var bCountry;
- var doneName, doneCountry;
-
- $.each($(this).find('field'), function(i, item)
- {
- var $item = $(item);
- if ($(item).attr('var').match(/^(fn|name|[^n][^i][^c][^k]name)$/gi) && doneName !== true) {
- bName = $item.children('value:first').text();
- doneName = true;
- } else if ($(item).attr('var').match(/^(ctry|country.*)$/gi) && doneCountry !== true) {
- bCountry = $item.children('value:first').text();
- doneCountry = true;
- }
- });
-
- var bXID = $(this).find('field[var="jid"] value:first').text();
- var dName = bName;
-
- // Override "undefined" value
- if(!bXID)
- bXID = '';
- if(!bName)
- bName = Common._e("Unknown name");
- if(!bCountry)
- bCountry = Common._e("Unknown country");
-
- // User hash
- var bHash = hex_md5(bXID);
-
- // HTML code
- var bHTML = '
' +
- '
' +
- '' +
- '
' +
- '
' + bName + '
' +
- '
' + bCountry + '
' +
- '
' + bXID + '
' +
- '
';
-
- // The buddy is not in our buddy list?
- if(!Common.exists('#roster .buddy[data-xid="' + escape(bXID) + '"]'))
- bHTML += '' + Common._e("Add") + '';
-
- // Chat button, if not in welcome/directory mode
- if(target == 'discovery')
- bHTML += '' + Common._e("Chat") + '';
-
- // Profile button, if not in discovery mode
- else
- bHTML += '' + Common._e("Profile") + '';
-
- // Close the HTML element
- bHTML += '
'
+ );
+ }
+
+ // Item with children
+ else {
+ // We display the waiting element
+ $(pathID + ' .disco-wait .disco-category-title').after(
+ '
' +
+ '' +
+ '
' + itemHost + '
' +
+ '
' + Common._e("Requesting this service...") + '
' +
+ '
'
+ );
+
+ // We display the category
+ $('#' + target + ' .disco-wait').show();
+
+ // We ask the server what's the service type
+ self.getType(itemHost, itemNode, sessionID);
+ }
+ });
+ }
+
+ // Else, there are no items for this query
+ else
+ self.noResult(pathID);
+ }
+
+ else if((type == 'muc') || (type == 'search') || (type == 'subscribe') || ((type == 'command') && $(handleXML).find('command').attr('xmlns'))) {
+ // Get some values
+ var xCommand = $(handleXML).find('command');
+ var bNode = xCommand.attr('node');
+ var bSession = xCommand.attr('sessionid');
+ var bStatus = xCommand.attr('status');
+ var xRegister = $(handleXML).find('query[xmlns="' + NS_REGISTER + '"]').text();
+ var xElement = $(handleXML).find('x');
+
+ // Search done
+ if((xElement.attr('type') == 'result') && (type == 'search')) {
+ var bPath = pathID;
+
+ // Display the result
+ $(handleXML).find('item').each(function() {
+ // Have some "flexibility" for what regards field names, it would be better to return the whole original DF
+ // layout, but on a large amount of result which have many fields, there's a very high chance the browser can
+ // choke on old systems or new ones even.
+
+ // Search for useful fields, return first result. This is rather hacky, but jQuery is horrible when it comes to
+ // matching st. using patterns. (TODO: Improve and return the full DF layout without choking the browser)
+ var bName;
+ var bCountry;
+ var doneName, doneCountry;
+
+ $.each($(this).find('field'), function(i, item) {
+ var $item = $(item);
+
+ if($(item).attr('var').match(/^(fn|name|[^n][^i][^c][^k]name)$/gi) && doneName !== true) {
+ bName = $item.children('value:first').text();
+ doneName = true;
+ } else if($(item).attr('var').match(/^(ctry|country.*)$/gi) && doneCountry !== true) {
+ bCountry = $item.children('value:first').text();
+ doneCountry = true;
+ }
+ });
+
+ var bXID = $(this).find('field[var="jid"] value:first').text();
+ var dName = bName;
+
+ // Override "undefined" value
+ if(!bXID)
+ bXID = '';
+ if(!bName)
+ bName = Common._e("Unknown name");
+ if(!bCountry)
+ bCountry = Common._e("Unknown country");
+
+ // User hash
+ var bHash = hex_md5(bXID);
+
+ // HTML code
+ var bHTML = '
' +
+ '
' +
+ '' +
+ '
' +
+ '
' + bName + '
' +
+ '
' + bCountry + '
' +
+ '
' + bXID + '
' +
+ '
';
+
+ // The buddy is not in our buddy list?
+ if(!Common.exists('#roster .buddy[data-xid="' + escape(bXID) + '"]')) {
+ bHTML += '' + Common._e("Add") + '';
+ }
+
+ // Chat button, if not in welcome/directory mode
+ if(target == 'discovery') {
+ bHTML += '' + Common._e("Chat") + '';
+ }
+
+ // Profile button, if not in discovery mode
+ else {
+ bHTML += '' + Common._e("Profile") + '';
+ }
+
+ // Close the HTML element
+ bHTML += '
';
-
+
// Append HTML code
$('body').append(html);
-
- // Click events
- $('#suggest .content a.one').click(function() {
- // Add/remove the active class
- $(this).toggleClass('active');
-
- // We require at least one room to be chosen
- if(Common.exists('#suggest .content a.one.active'))
- $('#suggest a.next').removeClass('disabled');
- else
- $('#suggest a.next').addClass('disabled');
-
- return false;
- });
-
- $('#suggest a.next').click(function() {
- // Disabled?
- if($(this).hasClass('disabled')) {
- return false;
- }
-
- // Store groupchats to join?
- if($(this).is('.continue')) {
- $('#suggest .content a.one.active').each(function() {
- JOIN_SUGGEST.push($(this).attr('data-xid'));
- });
- }
-
- // Switch to talk UI
- $('#suggest').remove();
- Connection.triggerConnected();
-
- return false;
- });
+
+ // Attach events
+ self._suggestCheckEvents();
} else {
- JOIN_SUGGEST = groupchat_arr;
-
+ self.join_suggest = groupchat_arr;
+
Connection.triggerConnected();
}
} catch(e) {
@@ -512,20 +641,26 @@ var Groupchat = (function () {
if(!ban_xid) {
Board.openThisInfo(6);
- Console.warning('Could not ban user with XID: ' + ban_xid + ' from room: ' + room_xid);
+ Console.warn('Could not ban user with XID: ' + ban_xid + ' from room: ' + room_xid);
} else {
// We generate the ban IQ
var iq = new JSJaCIQ();
iq.setTo(room_xid);
iq.setType('set');
-
+
var iqQuery = iq.setQuery(NS_MUC_ADMIN);
- var item = iqQuery.appendChild(iq.buildNode('item', {'affiliation': 'outcast', 'jid': ban_xid, 'xmlns': NS_MUC_ADMIN}));
-
+ var item = iqQuery.appendChild(iq.buildNode('item', {
+ 'affiliation': 'outcast',
+ 'jid': ban_xid,
+ 'xmlns': NS_MUC_ADMIN
+ }));
+
if(reason) {
- item.appendChild(iq.buildNode('reason', {'xmlns': NS_MUC_ADMIN}, reason));
+ item.appendChild(iq.buildNode('reason', {
+ 'xmlns': NS_MUC_ADMIN
+ }, reason));
}
-
+
con.send(iq, Errors.handleReply);
Console.log('Banned user with XID: ' + ban_xid + ' from room: ' + room_xid);
@@ -559,14 +694,20 @@ var Groupchat = (function () {
var iq = new JSJaCIQ();
iq.setTo(room_xid);
iq.setType('set');
-
+
var iqQuery = iq.setQuery(NS_MUC_ADMIN);
- var item = iqQuery.appendChild(iq.buildNode('item', {'nick': nick, 'role': 'none', 'xmlns': NS_MUC_ADMIN}));
-
+ var item = iqQuery.appendChild(iq.buildNode('item', {
+ 'nick': nick,
+ 'role': 'none',
+ 'xmlns': NS_MUC_ADMIN
+ }));
+
if(reason) {
- item.appendChild(iq.buildNode('reason', {'xmlns': NS_MUC_ADMIN}, reason));
+ item.appendChild(iq.buildNode('reason', {
+ 'xmlns': NS_MUC_ADMIN
+ }, reason));
}
-
+
con.send(iq, Errors.handleReply);
Console.info('Kicked user "' + nick + '" from room: ' + room_xid);
@@ -671,10 +812,54 @@ var Groupchat = (function () {
};
+ /**
+ * Sends initial configuration of the room
+ * @private
+ * @param {string} pid
+ * @param {string} xid
+ * @return {undefined}
+ */
+ self._initialConfiguration = function(pid, xid) {
+
+ try {
+ var iq = new JSJaCIQ();
+
+ iq.setTo(xid);
+ iq.setType('set');
+ iq.setID('first-muc-config-' + pid);
+
+ var iqQuery = iq.setQuery(NS_MUC_OWNER);
+
+ // Configure room with nil(null) fields
+ var iqX = iqQuery.appendChild(iq.buildNode('x', {
+ 'xmlns': NS_XDATA,
+ 'type': 'submit'
+ }));
+
+ // Build a new field node
+ var iqField = iqX.appendChild(iq.buildNode('field', {
+ 'var': 'FORM_TYPE',
+ 'type': 'hidden',
+ 'xmlns': NS_XDATA
+ }));
+
+ iqField.appendChild(iq.buildNode('value', {
+ 'xmlns': NS_XDATA
+ }, NS_MUC_CONFIG));
+
+ con.send(iq);
+
+ Console.info('Groupchat._initialConfiguration', 'Sent initial room configuration: ' + xid);
+ } catch(e) {
+ Console.error('Groupchat._initialConfiguration', e);
+ }
+ };
+
+
/**
* Return class scope
*/
return self;
-})();
\ No newline at end of file
+})();
diff --git a/source/app/javascripts/home.js b/source/app/javascripts/home.js
index a733181..06f8672 100644
--- a/source/app/javascripts/home.js
+++ b/source/app/javascripts/home.js
@@ -20,6 +20,119 @@ var Home = (function () {
var self = {};
+ /**
+ * Apply change events
+ * @private
+ * @param {object} current_sel
+ * @param {string} div
+ * @return {undefined}
+ */
+ self._eventsChange = function(current_sel, div) {
+
+ try {
+ // Create the attached events
+ switch(div) {
+ // Login tool
+ case 'loginer':
+ current_sel.find('a.to-anonymous').click(function() {
+ return self.change('anonymouser');
+ });
+
+ current_sel.find('a.advanced').click(self.showAdvanced);
+ current_sel.find('form').submit(self.loginForm);
+
+ break;
+
+ // Anonymous login tool
+ case 'anonymouser':
+ current_sel.find('a.to-home').click(function() {
+ return self.change('loginer');
+ });
+
+ current_sel.find('form').submit(Connection.doAnonymous);
+
+ // Keyup event on anonymous join's room input
+ current_sel.find('input.room').keyup(function() {
+ var value = $(this).val();
+ var report_sel = current_sel.find('.report');
+ var span_sel = current_sel.find('span');
+
+ if(!value) {
+ report_sel.hide();
+ span_sel.text('');
+ } else {
+ report_sel.show();
+ span_sel.text(JAPPIX_LOCATION + '?r=' + value);
+ }
+ });
+
+ break;
+
+ // Register tool
+ case 'registerer':
+ // Server input change
+ $('#home input.server').keyup(function(e) {
+ if($.trim($(this).val()) == HOST_MAIN) {
+ $('#home .captcha_grp').show();
+ $('#home input.captcha').removeAttr('disabled');
+ } else {
+ $('#home .captcha_grp').hide();
+ $('#home input.captcha').attr('disabled', true);
+ }
+ });
+
+ // Register input placeholder
+ // FIXME: breaks IE compatibility
+ //$('#home input[placeholder]').placeholder();
+
+ // Register form submit
+ current_sel.find('form').submit(self.registerForm);
+
+ break;
+ }
+ } catch(e) {
+ Console.error('Home._eventsChange', e);
+ }
+
+ };
+
+
+ /**
+ * Create obsolete form
+ * @private
+ * @param {string} home
+ * @param {string} locale
+ * @return {undefined}
+ */
+ self._obsolete = function(home, locale) {
+
+ try {
+ // Add the code
+ $(locale).after(
+ '
' +
+ '
' + Common._e("Your browser is out of date!") + '
' +
+
+ '' +
+ '' +
+ '' +
+ '' +
+ '' +
+ '
'
+ );
+
+ // Display it later
+ $(home + '.obsolete').oneTime('1s', function() {
+ $(this).slideDown();
+ });
+
+ Console.warn('Jappix does not support this browser!');
+ } catch(e) {
+ Console.error('Home._obsolete', e);
+ }
+
+ };
+
+
/**
* Allows the user to switch the difference home page elements
* @public
@@ -33,19 +146,19 @@ var Home = (function () {
var home = '#home .';
var right = home + 'right ';
var current = right + '.homediv.' + div;
-
+
// We switch the div
$(right + '.homediv, ' + right + '.top').hide();
$(right + '.' + div).show();
-
+
// We reset the homedivs
$(home + 'homediv:not(.default), ' + home + 'top:not(.default)').remove();
-
+
// Get the HTML code to display
var disable_form = '';
var lock_host = '';
var code = '';
-
+
// Apply the previous link
switch(div) {
case 'loginer':
@@ -54,196 +167,144 @@ var Home = (function () {
if(!Common.exists(right + '.top.sub')) {
// Append the HTML code for previous link
$(right + '.top.default').after('
');
-
+
// Click event on previous link
$(home + 'top.sub a.previous').click(function() {
return self.change('default');
});
}
-
+
break;
}
-
+
// Apply the form
switch(div) {
// Login tool
case 'loginer':
lock_host = Utils.disableInput(LOCK_HOST, 'on');
- code = '
' + Common.printf(Common._e("Login to your existing XMPP account. You can also use the %s to join a groupchat."), '' + Common._e("anonymous mode") + '') + '
' + Common.printf(Common._e("Enter the groupchat you want to join and the nick you want to have. You can also go back to the %s."), '' + Common._e("login page") + '') + '