1
0
Fork 0
mirror of https://github.com/YunoHost-Apps/jappix_ynh.git synced 2024-09-03 19:26:19 +02:00

Update sources to Jappix 1.1.0

This commit is contained in:
mbugeia 2014-11-25 20:12:58 +01:00
parent 3f6874b78a
commit cd9dd26e14
688 changed files with 56044 additions and 180105 deletions

11
source/.gitignore vendored Normal file
View file

@ -0,0 +1,11 @@
mini/
store/
tmp/cache/
tmp/jingle/
tmp/avatar/
tmp/archives/
tmp/send/
log/
test/node_modules/
.DS_Store
*.esproj

View file

@ -4,6 +4,57 @@ Jappix Changelog
Here's the log of what has changed over the Jappix releases.
Primo, v1.1.0 (Jun 2014)
------------------------
* XEP-0272: Multiparty Jingle (Muji) @valeriansaliou
* Prevent client crash on huge messages @valeriansaliou
* Beautified client code (JavaScript) @valeriansaliou
* Fix unavailable MUC rooms @emamirazavi
One, v1.0.7 (May 2014)
----------------------
* Fix BackLinks design @valeriansaliou
* Sort Jappix Mobile contacts alphabetically @valeriansaliou
* Display offline contacts in Jappix Mini @valeriansaliou
One, v1.0.6 (May 2014)
----------------------
* XEP-0308: Last Message Correction @valeriansaliou
* XEP-0333: Chat Markers @valeriansaliou
* XEP-0319: Last User Interaction into Presence @valeriansaliou
* XEP-0224: Attention @valeriansaliou
* XEP-0152: Reachability Addresses @valeriansaliou
* XEP-0334: Message Processing Hints @valeriansaliou
* Fix gateway contacts management @valeriansaliou
* Fix sounds in Jappix Mini @aryo, @valeriansaliou
One, v1.0.5 (May 2014)
----------------------
* Fix MUC bookmark shortcut button @valeriansaliou
* Fix HTML5 notifications in Firefox 22+ @valeriansaliou
* Fix server commands tool @valeriansaliou
* New translations added (Uzbek), and a few ones updated @nurkamol, @valeriansaliou
One, v1.0.4 (May 2014)
----------------------
* Fix update tool (on some environments) @valeriansaliou
* Fix MUC room join @maranda, @valeriansaliou
* Fix special chars in JIDs for Jappix Mini @dunger, @valeriansaliou
* Fix WebSocket session termination in JSJaC @sstrigler
* Enhance backend security (verify SSL certificates) @valeriansaliou
* Add assets client cache option @valeriansaliou
* Add SSO support to Jappix Mobile @valeriansaliou
One, v1.0.3 (March 2014)
------------------------

View file

@ -11,56 +11,75 @@ Here are listed the XMPP Protocol Extensions that Jappix supports, as well as th
* RFC-6122: Extensible Messaging and Presence Protocol (XMPP): Address Format
# XMPP Extensions
# XMPP Extensions (Standardized)
* XEP-0045: Multi-User Chat *v1.25*
* XEP-0004: Data Forms *v2.9*
* XEP-0012: Last Activity *v2.0*
* XEP-0016: Privacy Lists *v1.6*
* XEP-0030: Service Discovery *v2.4*
* XEP-0045: Multi-User Chat *v1.25*
* XEP-0049: Private XML Storage *v1.2*
* XEP-0050: Ad-Hoc Commands *v1.2*
* XEP-0054: vcard-temp *v1.2*
* XEP-0055: Jabber Search *v1.3*
* XEP-0060: Publish-Subscribe *v1.13*
* XEP-0124: Bidirectional-streams Over Synchronous HTTP (BOSH) *v1.10*
* XEP-0115: Entity Capabilities *v1.5*
* XEP-0066: Out of Band Data *v1.5*
* XEP-0071: XHTML-IM *v1.5*
* XEP-0072: SOAP Over XMPP *v1.0*
* XEP-0077: In-Band Registration *v2.4*
* XEP-0080: User Location *v1.7*
* XEP-0084: User Avatar *v1.1*
* XEP-0085: Chat State Notifications *v2.1*
* XEP-0092: Software Version *v1.1*
* XEP-0107: User Mood *v1.2*
* XEP-0108: User Activity *v1.3*
* XEP-0115: Entity Capabilities *v1.5*
* XEP-0118: User Tune *v1.2*
* XEP-0080: User Location *v1.7*
* XEP-0172: User Nickname *v1.1*
* XEP-0084: User Avatar *v1.1*
* XEP-0277: Microblogging over XMPP *v0.6*
* XEP-xxxx: Notification Inbox *v0.1*
* Alternate URL: http://xmpp.org/extensions/inbox/notification-inbox.html
* XEP-0203: Delayed Delivery *v2.0*
* XEP-0124: Bidirectional-streams Over Synchronous HTTP (BOSH) *v1.10*
* XEP-0144: Roster Item Exchange *v1.0*
* XEP-0072: SOAP Over XMPP *v1.0*
* XEP-0085: Chat State Notifications *v2.1*
* XEP-0071: XHTML-IM *v1.5*
* XEP-0313: Message Archive Management *v0.3*
* Alternate URL: https://demo.frenchtouch.pro/valerian.saliou/xmpp/extensions/xep-0313.html
* XEP-0012: Last Activity *v2.0*
* XEP-0049: Private XML Storage *v1.2*
* XEP-0077: In-Band Registration *v2.4*
* XEP-0055: Jabber Search *v1.3*
* XEP-0050: Ad-Hoc Commands *v1.2*
* XEP-0092: Software Version *v1.1*
* XEP-0004: Data Forms *v2.9*
* XEP-0054: vcard-temp *v1.2*
* XEP-0202: Entity Time *v2.0*
* XEP-0199: XMPP Ping *v2.0*
* XEP-0184: Message Delivery Receipts *v1.2*
* XEP-0016: Privacy Lists *v1.6*
* XEP-0066: Out of Band Data *v1.5*
* XEP-0280: Message Carbons *v0.9*
* XEP-0292: vCard4 Over XMPP *v0.10*
* XEP-0152: Reachability Addresses *v1.0*
* XEP-0166: Jingle *v1.1*
* XEP-0167: Jingle RTP Sessions *v1.1*
* XEP-0172: User Nickname *v1.1*
* XEP-0176: Jingle ICE-UDP Transport Method *v1.0*
* XEP-0177: Jingle Raw UDP Transport Method *v1.1*
* XEP-0184: Message Delivery Receipts *v1.2*
* XEP-0199: XMPP Ping *v2.0*
* XEP-0202: Entity Time *v2.0*
* XEP-0203: Delayed Delivery *v2.0*
* XEP-0224: Attention *v1.0*
* XEP-0215: External Service Discovery *v0.5*
* XEP-0249: Direct MUC Invitations *v1.2*
* XEP-0262: Use of ZRTP in Jingle RTP Sessions *v1.0*
* XEP-0266: Codecs for Jingle Audio *v1.0*
* XEP-0269: Jingle Early Media *v0.1*
* XEP-0277: Microblogging over XMPP *v0.6*
* XEP-0278: Jingle Relay Nodes *v0.2*
* XEP-0280: Message Carbons *v0.9*
* XEP-0292: vCard4 Over XMPP *v0.10*
* XEP-0293: Jingle RTP Feedback Negotiation *v0.1*
* XEP-0294: Jingle RTP Header Extensions Negotiation *v0.1*
* XEP-0299: Codecs for Jingle Video *v0.1*
* XEP-0308: Last Message Correction *v1.0*
* XEP-0319: Last User Interaction in Presence *v0.2*
* XEP-0320: Use of DTLS-SRTP in Jingle Sessions *v0.2*
* XEP-0333: Chat Markers *v0.2*
* XEP-0334: Message Processing Hints *v0.1*
* XEP-0338: Jingle Grouping Framework *v0.1*
* XEP-0339: Source-Specific Media Attributes in Jingle *v0.1*
# XMPP Extensions (Updated)
* XEP-0272: Multiparty Jingle (Muji) *v0.2*
* Alternate URL: https://demo.frenchtouch.pro/valerian.saliou/xmpp/extensions/xep-0272.html
* XEP-0313: Message Archive Management *v0.3*
* Alternate URL: https://demo.frenchtouch.pro/valerian.saliou/xmpp/extensions/xep-0313.html
# XMPP Extensions (Proposed)
* XEP-xxxx: Notification Inbox *v0.1*
* Alternate URL: http://xmpp.org/extensions/inbox/notification-inbox.html
# Others

View file

@ -32,9 +32,9 @@ Start translating on https://www.transifex.com/projects/p/jappix/ (new translato
Links
-----
* Jappix project website: http://jappix.org/
* Jappix project website: https://jappix.org/
* Jappix project dev panel: https://github.com/jappix/jappix
* Jappix nodes list: http://jappix.net/
* Jappix nodes list: https://jappix.net/
* Jappix main service: https://jappix.com/
* Jappix commercial support: https://jappix.pro/

View file

@ -1 +1 @@
One [1.0.3]
Primo [1.1.0]

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8" ?>
<jappix xmlns="jappix:file:get">
<css>fonts.css~main.css~images.css~board.css~home.css~others.css~tools.css~roster.css~myinfos.css~pageengine.css~channel.css~pageswitch.css~smileys.css~popup.css~vcard.css~options.css~favorites.css~discovery.css~directory.css~adhoc.css~privacy.css~inbox.css~mucadmin.css~integratebox.css~userinfos.css~search.css~welcome.css~me.css~rosterx.css~jingle.css</css>
<js>origin.js~jxhr.js~datejs.js~jquery.js~jquery.ui.js~jquery.json.js~jquery.form.js~jquery.timers.js~jquery.placeholder.js~jquery.textrange.js~base64.js~jsjac.js~jsjac.jingle.js~system.js~constants.js~datastore.js~browser-detect.js~home.js~talk.js~popup.js~audio.js~board.js~bubble.js~chat.js~groupchat.js~smileys.js~oob.js~avatar.js~mucadmin.js~connection.js~dataform.js~discovery.js~directory.js~adhoc.js~privacy.js~errors.js~name.js~favorites.js~features.js~interface.js~xmpplinks.js~iq.js~message.js~chatstate.js~receipts.js~tooltip.js~filter.js~links.js~inbox.js~microblog.js~music.js~notification.js~httpreply.js~options.js~integratebox.js~pubsub.js~pep.js~presence.js~roster.js~jingle.js~storage.js~console.js~common.js~utilities.js~date.js~caps.js~vcard.js~userinfos.js~search.js~autocompletion.js~welcome.js~me.js~rosterx.js~mam.js~carbons.js</js>
<css>fonts.css~main.css~images.css~board.css~home.css~others.css~tools.css~roster.css~myinfos.css~pageengine.css~channel.css~pageswitch.css~smileys.css~popup.css~vcard.css~options.css~favorites.css~discovery.css~directory.css~adhoc.css~privacy.css~inbox.css~mucadmin.css~integratebox.css~userinfos.css~search.css~welcome.css~me.css~rosterx.css~call.css~jingle.css~muji.css</css>
<js>origin.js~jxhr.js~datejs.js~jquery.js~jquery.ui.js~jquery.json.js~jquery.form.js~jquery.timers.js~jquery.placeholder.js~jquery.textrange.js~jquery.scrollto.js~base64.js~jsjac.js~jsjac.jingle.js~system.js~constants.js~datastore.js~browser-detect.js~home.js~talk.js~popup.js~audio.js~board.js~bubble.js~chat.js~groupchat.js~smileys.js~oob.js~avatar.js~mucadmin.js~connection.js~dataform.js~discovery.js~directory.js~adhoc.js~privacy.js~errors.js~name.js~favorites.js~features.js~interface.js~xmpplinks.js~iq.js~message.js~chatstate.js~receipts.js~tooltip.js~filter.js~links.js~inbox.js~microblog.js~music.js~notification.js~httpreply.js~options.js~integratebox.js~pubsub.js~pep.js~presence.js~roster.js~call.js~jingle.js~muji.js~storage.js~console.js~common.js~utilities.js~date.js~caps.js~vcard.js~userinfos.js~search.js~autocompletion.js~welcome.js~me.js~rosterx.js~mam.js~carbons.js~correction.js~markers.js~attention.js</js>
</jappix>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View file

@ -142,9 +142,7 @@ var AdHoc = (function () {
try {
// Click event
$('#adhoc .bottom .finish').click(
self.close()
);
$('#adhoc .bottom .finish').click(self.close);
} catch(e) {
Console.error('AdHoc.launch', e);
}

View file

@ -20,6 +20,28 @@ var Anonymous = (function () {
var self = {};
/**
* Registers connection handlers
* @private
* @param {object} con
* @return {undefined}
*/
self._registerHandlers = function(con) {
try {
con.registerHandler('message', Message.handle);
con.registerHandler('presence', Presence.handle);
con.registerHandler('iq', IQ.handle);
con.registerHandler('onconnect', self.connected);
con.registerHandler('onerror', Errors.handle);
con.registerHandler('ondisconnect', self.disconnected);
} catch(e) {
Console.error('Anonymous._registerHandlers', e);
}
};
/**
* Connected to an anonymous session
* @public
@ -115,12 +137,7 @@ var Anonymous = (function () {
}
// And we handle everything that happen
con.registerHandler('message', Message.handle);
con.registerHandler('presence', Presence.handle);
con.registerHandler('iq', IQ.handle);
con.registerHandler('onconnect', self.connected);
con.registerHandler('onerror', Errors.handle);
con.registerHandler('ondisconnect', self.disconnected);
self._registerHandlers(con);
// We set the anonymous connection parameters
oArgs = {};
@ -165,10 +182,13 @@ var Anonymous = (function () {
Interface.showGeneralWait();
// Get the vars
if(XMPPLinks.links_var.r)
if(XMPPLinks.links_var.r) {
ANONYMOUS_ROOM = XMPPLinks.links_var.r;
if(XMPPLinks.links_var.n)
}
if(XMPPLinks.links_var.n) {
ANONYMOUS_NICK = XMPPLinks.links_var.n;
}
// Fire the login action
self.login(HOST_ANONYMOUS);

View file

@ -0,0 +1,216 @@
/*
Jappix - An open social platform
Implementation of XEP-0224: Attention
-------------------------------------------------
License: AGPL
Author: Valérian Saliou
*/
// Bundle
var Attention = (function () {
/**
* Alias of this
* @private
*/
var self = {};
/**
* Displays attention message
* @private
* @param {string} xid
* @param {string} body
* @return {undefined}
*/
self._display = function(xid, body, mode) {
try {
var name = Name.getBuddy(xid).htmlEnc();
var hash = hex_md5(xid);
// Compute some variables
var message = Common._e(Common.printf("You requested %s's attention to the conversation", name));
if(mode == 'him') {
message = Common._e(Common.printf("%s requested your attention to the conversation", name));
}
if(body) {
message += ' (' + body + ')';
}
// Display notification
Message.display(
'chat',
xid,
hash,
name,
message,
DateUtils.getCompleteTime(),
DateUtils.getTimeStamp(),
'system-message',
true,
undefined,
mode
);
// Add a marker to displayed message
$('#' + hash + ' .content .one-line.system-message:last').addClass('attention-notice');
} catch(e) {
Console.error('Attention._display', e);
}
};
/**
* Sends attention stanza
* @private
* @param {string} xid
* @param {string} body
* @return {object}
*/
self._stanza = function(xid, body) {
try {
var message = new JSJaCMessage();
message.setType('headline');
message.setTo(xid);
if(body) {
message.setBody(body);
}
// Attention node
message.appendNode('attention', {
'xmlns': NS_URN_ATTENTION
});
con.send(message);
return message;
} catch(e) {
Console.error('Attention._stanza', e);
}
};
/**
* Returns whether last attention message exists or not
* @private
* @param {string} xid
* @return {boolean}
*/
self._lastExists = function(xid, mode) {
var last_exists = false;
try {
var line_sel = $('#' + hex_md5(xid) + ' .content .one-line[data-mode="' + mode + '"]:last');
last_exists = line_sel.is('.system-message.attention-notice') ? true : false;
} catch(e) {
Console.error('Attention._lastExists', e);
} finally {
return last_exists;
}
};
/**
* Return whether entity supports attention notifications
* @public
* @param {string} xid
* @return {boolean}
*/
self.hasSupport = function(xid) {
var has_support = false;
try {
has_support = true ? $('#' + hex_md5(xid)).attr('data-attention') == 'true' : false;
} catch(e) {
Console.error('Attention.hasSupport', e);
} finally {
return has_support;
}
};
/**
* Send an attention message
* @public
* @param {string} xid
* @param {string} body
* @return {undefined}
*/
self.send = function(xid, body) {
try {
var mode = 'me';
// Don't send attention message twice
if(self._lastExists(xid, mode) === false) {
// Send message stanza
self._stanza(xid, body);
// Display attention notification
self._display(xid, body, mode);
} else {
Console.debug('Attention.send', 'Not sending attention message to: ' + xid + ' because already sent.');
}
} catch(e) {
Console.error('Attention.send', e);
}
};
/**
* Receive an attention notification
* @public
* @param {string} xid
* @return {undefined}
*/
self.receive = function(xid, body) {
try {
var mode = 'him';
var hash = hex_md5(xid);
// Don't receive attention message twice
if((self._lastExists(xid, mode) === false) && Common.exists('#' + hash)) {
// Display attention notification
self._display(xid, body, mode);
// Show a notification
Interface.messageNotify(hash, 'personal');
Audio.play('catch-attention');
Board.quick(
xid,
'chat',
Common._e("Attention to conversation requested."),
Name.getBuddy(xid)
);
}
} catch(e) {
Console.error('Attention.receive', e);
}
};
/**
* Return class scope
*/
return self;
})();

View file

@ -29,7 +29,7 @@ var Audio = (function () {
* @private
* @return {boolean}
*/
self._is_supported = function() {
self._isSupported = function() {
is_supported = true;
@ -38,7 +38,7 @@ var Audio = (function () {
is_supported = false;
}
} catch(e) {
Console.error('Audio._is_supported', e);
Console.error('Audio._isSupported', e);
} finally {
return is_supported;
}
@ -46,6 +46,57 @@ var Audio = (function () {
};
/**
* Append audio DOM code
* @private
* @return {undefined}
*/
self._appendDOM = function() {
try {
// If the audio elements aren't yet in the DOM
if(!Common.exists('#audio')) {
$('body').append(
'<div id="audio">' +
'<audio id="new-chat" preload="auto" data-duration="2">' +
'<source src="' + './sounds/new-chat.mp3' + '" />' +
'<source src="' + './sounds/new-chat.oga' + '" />' +
'</audio>' +
'<audio id="receive-message" preload="auto" data-duration="2">' +
'<source src="' + './sounds/receive-message.mp3' + '" />' +
'<source src="' + './sounds/receive-message.oga' + '" />' +
'</audio>' +
'<audio id="notification" preload="auto" data-duration="2">' +
'<source src="' + './sounds/notification.mp3' + '" />' +
'<source src="' + './sounds/notification.oga' + '" />' +
'</audio>' +
'<audio id="catch-attention" preload="auto" data-duration="3">' +
'<source src="' + './sounds/catch-attention.mp3' + '" />' +
'<source src="' + './sounds/catch-attention.oga' + '" />' +
'</audio>' +
'<audio id="incoming-call" preload="auto" data-duration="7">' +
'<source src="' + './sounds/incoming-call.mp3' + '" />' +
'<source src="' + './sounds/incoming-call.oga' + '" />' +
'</audio>' +
'<audio id="outgoing-call" preload="auto" data-duration="30">' +
'<source src="' + './sounds/outgoing-call.mp3' + '" />' +
'<source src="' + './sounds/outgoing-call.oga' + '" />' +
'</audio>' +
'</div>'
);
}
} catch(e) {
Console.error('Audio._appendDOM', e);
}
};
/**
* Plays the given sound ID
* @public
@ -58,43 +109,13 @@ var Audio = (function () {
repeat = (typeof repeat === 'boolean') ? repeat : false;
// Not supported?
if(!self._is_supported()) {
if(!self._isSupported()) {
return false;
}
// If the sounds are enabled
if(DataStore.getDB(Connection.desktop_hash, 'options', 'sounds') === '1') {
// If the audio elements aren't yet in the DOM
if(!Common.exists('#audio')) {
$('body').append(
'<div id="audio">' +
'<audio id="new-chat" preload="auto" data-duration="2">' +
'<source src="' + './sounds/new-chat.mp3' + '" />' +
'<source src="' + './sounds/new-chat.oga' + '" />' +
'</audio>' +
'<audio id="receive-message" preload="auto" data-duration="2">' +
'<source src="' + './sounds/receive-message.mp3' + '" />' +
'<source src="' + './sounds/receive-message.oga' + '" />' +
'</audio>' +
'<audio id="notification" preload="auto" data-duration="2">' +
'<source src="' + './sounds/notification.mp3' + '" />' +
'<source src="' + './sounds/notification.oga' + '" />' +
'</audio>' +
'<audio id="incoming-call" preload="auto" data-duration="7">' +
'<source src="' + './sounds/incoming-call.mp3' + '" />' +
'<source src="' + './sounds/incoming-call.oga' + '" />' +
'</audio>' +
'<audio id="outgoing-call" preload="auto" data-duration="30">' +
'<source src="' + './sounds/outgoing-call.mp3' + '" />' +
'<source src="' + './sounds/outgoing-call.oga' + '" />' +
'</audio>' +
'</div>'
);
}
self._appendDOM();
// We play the target sound
var audio_raw_sel = $('#audio audio').filter('#' + name);
@ -146,7 +167,7 @@ var Audio = (function () {
try {
// Not supported?
if(!self._is_supported()) {
if(!self._isSupported()) {
return false;
}

View file

@ -32,14 +32,17 @@ var Autocompletion = (function () {
try {
// Put the two strings into lower case
var sA = a[0].toLowerCase();
var sB = b[0].toLowerCase();
var sort_a = a[0].toLowerCase();
var sort_b = b[0].toLowerCase();
// Process the sort
if(sA > sB)
if(sort_a > sort_b) {
return 1;
if(sA < sB)
}
if(sort_a < sort_b) {
return -1;
}
} catch(e) {
Console.error('Autocompletion.caseInsensitiveSort', e);
}
@ -49,40 +52,51 @@ var Autocompletion = (function () {
/**
* Split a query into its subqueries ready to be used in autocompletion
* The function return an array containing two others : the first with subqueries
* and the second with remaining parts
* For example, if query is "A B C", the subqueries are ["C", "B C", "A B C"] and
* the remaining parts are ["A B ", "A ", ""]
* @public
* @param {string} query
* @return {Array}
* @return {object}
*/
self.getSubQueries = function(query) {
var subqueries = [];
var remnants = [];
var result = [];
var queryLastCharPos = query.length - 1;
var spaceCounter = 0;
for (var i=queryLastCharPos; i>=0; i--) {
// Search from the end of the query
var iChar = query.charAt(i);
if (spaceCounter === 0 && iChar.search(/\s/) === 0) {
// the first "local" space was found
// add the subquery and its remnant to results
subqueries.push(query.slice(i+1));
remnants.push(query.slice(0, i+1));
spaceCounter++;
} else {
spaceCounter = 0;
try {
var subqueries = [];
var remnants = [];
var query_last_char_pos = query.length - 1;
var space_counter = 0;
var cur_char;
for(var i = query_last_char_pos; i >= 0; i--) {
// Search from the end of the query
cur_char = query.charAt(i);
if(space_counter === 0 && cur_char.search(/\s/) === 0) {
// The first "local" space was found
// Add the subquery and its remnant to results
subqueries.push(query.slice(i+1));
remnants.push(query.slice(0, i+1));
space_counter++;
} else {
space_counter = 0;
}
}
}
if (spaceCounter === 0) {
// If the first char of the query is not a space, add the full query to results
subqueries.push(query);
remnants.push("");
if(space_counter === 0) {
// If the first char of the query is not a space, add the full query to results
subqueries.push(query);
remnants.push('');
}
result = [subqueries, remnants];
} catch(e) {
Console.error('Autocompletion.getSubQueries', e);
} finally {
return result;
}
return [subqueries, remnants];
};
@ -102,25 +116,37 @@ var Autocompletion = (function () {
try {
// Replace forbidden characters in regex
query = Common.escapeRegex(query);
// Build an array of regex to use
var queryRegExp = [];
for (i = 0; i<query.length; i++) {
if (query[i] !== null) {
queryRegExp.push(new RegExp('(^)' + query[i], 'gi'));
var query_reg_exp = [];
for(i = 0; i < query.length; i++) {
if(query[i] !== null) {
query_reg_exp.push(
new RegExp('(^)' + query[i], 'gi')
);
}
}
// Search in the roster
var nick, regex;
$('#' + id + ' .user').each(function() {
var nick = $(this).find('.name').text();
for (i = 0; i<queryRegExp.length; i++) {
var regex = queryRegExp[i];
nick = $(this).find('.name').text();
for(i = 0; i < query_reg_exp.length; i++) {
regex = query_reg_exp[i];
if(nick.match(regex)) {
results.push([nick, i]);
}
}
});
// Sort the array
results = results.sort(self.caseInsensitiveSort);
results = results.sort(
self.caseInsensitiveSort
);
} catch(e) {
Console.error('Autocompletion.process', e);
} finally {
@ -139,7 +165,8 @@ var Autocompletion = (function () {
self.reset = function(hash) {
try {
$('#' + hash + ' .message-area').removeAttr('data-autocompletion-pointer').removeAttr('data-autocompletion-query');
$('#' + hash + ' .message-area').removeAttr('data-autocompletion-pointer')
.removeAttr('data-autocompletion-query');
} catch(e) {
Console.error('Autocompletion.reset', e);
}
@ -157,36 +184,34 @@ var Autocompletion = (function () {
try {
// Initialize
var vSelector = $('#' + hash + ' .message-area');
var value = vSelector.val();
var message_area_sel = $('#' + hash + ' .message-area');
var value = message_area_sel.val();
if(!value) {
self.reset(hash);
}
var query = vSelector.attr('data-autocompletion-query');
var query = message_area_sel.attr('data-autocompletion-query');
if(query === undefined) {
// The autocompletion has not been yet launched
query = self.getSubQueries(value);
vSelector.attr('data-autocompletion-query', JSON.stringify(query));
message_area_sel.attr('data-autocompletion-query', JSON.stringify(query));
} else {
// The autocompletion has already stored a query
query = JSON.parse(query);
}
// Get the pointer
var pointer = vSelector.attr('data-autocompletion-pointer');
var i = 0;
if(pointer)
i = parseInt(pointer);
var pointer = message_area_sel.attr('data-autocompletion-pointer');
var i = pointer ? parseInt(pointer, 10) : 0;
// We get the nickname
var nickResult = self.process(query[0], hash)[i];
var nick_result = self.process(query[0], hash)[i];
var nick;
if (nickResult !== undefined) {
nick = nickResult[0];
if(nick_result !== undefined) {
nick = nick_result[0];
}
// Shit, this is my nick!
@ -195,21 +220,26 @@ var Autocompletion = (function () {
i++;
// Get the next nick
nickResult = self.process(query[0], hash)[i];
if (nickResult !== undefined) {
nick = nickResult[0];
nick_result = self.process(query[0], hash)[i];
if (nick_result !== undefined) {
nick = nick_result[0];
}
}
// We quote the nick
if((nickResult !== undefined) && (nick !== undefined)) {
if((nick_result !== undefined) && (nick !== undefined)) {
// Increment
i++;
var message = query[1][nickResult[1]];
Utils.quoteMyNick(hash, nick, message);
Utils.quoteMyNick(
hash,
nick,
query[1][nick_result[1]]
);
// Put a pointer
vSelector.attr('data-autocompletion-pointer', i);
message_area_sel.attr('data-autocompletion-pointer', i);
}
} catch(e) {
Console.error('Autocompletion.create', e);

View file

@ -39,8 +39,9 @@ var Avatar = (function () {
try {
// No need to get the avatar, another process is yet running
if(Utils.existArrayValue(self.pending, xid))
if(Utils.existArrayValue(self.pending, xid)) {
return false;
}
// Initialize: XML data is in one SQL entry, because some browser are sloooow with SQL requests
var xml = Common.XMLFromString(
@ -49,8 +50,9 @@ var Avatar = (function () {
var forced = false;
// Retrieving forced?
if($(xml).find('forced').text() == 'true')
if($(xml).find('forced').text() == 'true') {
forced = true;
}
// No avatar in presence
if(!photo && !forced && enabled == 'true') {
@ -72,8 +74,9 @@ var Avatar = (function () {
var updated = false;
// Process the checksum of the avatar
if(checksum == photo || photo == 'forget' || forced)
if(checksum == photo || photo == 'forget' || forced) {
updated = true;
}
// If the avatar is yet stored and a new retrieving is not needed
if(mode == 'cache' && type && binval && checksum && updated) {
@ -141,8 +144,9 @@ var Avatar = (function () {
oChecksum = DataStore.getDB(Connection.desktop_hash, 'checksum', 1);
// Avoid the "null" value
if(!oChecksum)
if(!oChecksum) {
oChecksum = '';
}
}
// vCard not empty?
@ -151,10 +155,12 @@ var Avatar = (function () {
if(handleFrom == Common.getXID()) {
// Get the names
var names = Name.generateBuddy(iq);
var phone_number = find.find('TEL:has(NUMBER):first NUMBER:first').text();
// Write the values to the database
DataStore.setDB(Connection.desktop_hash, 'profile', 'name', names[0]);
DataStore.setDB(Connection.desktop_hash, 'profile', 'nick', names[1]);
DataStore.setDB(Connection.desktop_hash, 'profile', 'phone', phone_number);
}
// We get the avatar
@ -170,12 +176,11 @@ var Avatar = (function () {
// Enough data
else {
// No type?
if(!aType)
if(!aType) {
aType = 'image/png';
// Process the checksum
else
} else {
aChecksum = hex_sha1(Base64.decode(aBinval));
}
}
// We display the user avatar
@ -197,17 +202,19 @@ var Avatar = (function () {
// Define a proper checksum
var pChecksum = aChecksum;
if(pChecksum == 'none')
if(pChecksum == 'none') {
pChecksum = '';
}
// Update our temp. checksum
DataStore.setDB(Connection.desktop_hash, 'checksum', 1, pChecksum);
// Send the stanza
if(!Presence.first_sent)
if(!Presence.first_sent) {
Storage.get(NS_OPTIONS);
else if(DataStore.hasPersistent())
} else if(DataStore.hasPersistent()) {
Presence.sendActions(pChecksum);
}
}
} catch(e) {
Console.error('Avatar.handle', e);
@ -255,10 +262,11 @@ var Avatar = (function () {
var code = '<img class="avatar" src="';
// If the avatar exists
if((type != 'none') && (binval != 'none'))
if((type != 'none') && (binval != 'none')) {
code += 'data:' + type + ';base64,' + binval;
else
} else {
code += './images/others/default-avatar.png';
}
code += '" alt="" />';

View file

@ -20,6 +20,137 @@ var Board = (function () {
var self = {};
/* Contants */
self.NOTIFICATION = (window.Notification || window.mozNotification || window.webkitNotification);
/**
* Generate board info message
* @private
* @param {string} id
* @return {string}
*/
self._generateBoardInfo = function(id) {
var text = null;
try {
switch(id) {
// Password change
case 1:
text = Common._e("Your password has been changed, now you can connect to your account with your new login data.");
break;
// Account deletion
case 2:
text = Common._e("Your XMPP account has been removed, bye!");
break;
// Account logout
case 3:
text = Common._e("You have been logged out of your XMPP account, have a nice day!");
break;
// Groupchat join
case 4:
text = Common._e("The room you tried to join doesn't seem to exist.");
break;
// Groupchat removal
case 5:
text = Common._e("The groupchat has been removed.");
break;
// Non-existant groupchat user
case 6:
text = Common._e("The user that you want to reach is not present in the room.");
break;
}
} catch(e) {
Console.error('Board._generateBoardInfo', e);
} finally {
return text;
}
};
/**
* Generate board error message
* @private
* @param {string} id
* @return {string}
*/
self._generateBoardError = function(id) {
var text = null;
try {
switch(id) {
// Custom error
case 1:
text = '<b>' + Common._e("Error") + '</b> &raquo; <span></span>';
break;
// Network error
case 2:
text = Common._e("Jappix has been interrupted by a network issue, a bug or bad login (check that you entered the right credentials), sorry for the inconvenience.");
break;
// List retrieving error
case 3:
text = Common._e("The element list on this server could not be obtained!");
break;
// Attaching error
case 4:
text = Common.printf(Common._e("An error occured while uploading your file: maybe it is too big (%s maximum) or forbidden!"), JAPPIX_MAX_UPLOAD);
break;
}
} catch(e) {
Console.error('Board._generateBoardError', e);
} finally {
return text;
}
};
/**
* Attaches board events
* @private
* @param {object} board_sel
* @return {undefined}
*/
self._attachEvents = function(board_sel) {
try {
board_sel.click(function() {
self.closeThis(this);
});
board_sel.oneTime('5s', function() {
self.closeThis(this);
});
board_sel.slideDown();
} catch(e) {
Console.error('Board._attachEvents', e);
}
};
/**
* Creates a board panel
* @public
@ -35,93 +166,25 @@ var Board = (function () {
// Info
if(type == 'info') {
switch(id) {
// Password change
case 1:
text = Common._e("Your password has been changed, now you can connect to your account with your new login data.");
break;
// Account deletion
case 2:
text = Common._e("Your XMPP account has been removed, bye!");
break;
// Account logout
case 3:
text = Common._e("You have been logged out of your XMPP account, have a nice day!");
break;
// Groupchat join
case 4:
text = Common._e("The room you tried to join doesn't seem to exist.");
break;
// Groupchat removal
case 5:
text = Common._e("The groupchat has been removed.");
break;
// Non-existant groupchat user
case 6:
text = Common._e("The user that you want to reach is not present in the room.");
break;
}
}
// Error
else {
switch(id) {
// Custom error
case 1:
text = '<b>' + Common._e("Error") + '</b> &raquo; <span></span>';
break;
// Network error
case 2:
text = Common._e("Jappix has been interrupted by a network issue, a bug or bad login (check that you entered the right credentials), sorry for the inconvenience.");
break;
// List retrieving error
case 3:
text = Common._e("The element list on this server could not be obtained!");
break;
// Attaching error
case 4:
text = Common.printf(Common._e("An error occured while uploading your file: maybe it is too big (%s maximum) or forbidden!"), JAPPIX_MAX_UPLOAD);
break;
}
text = self._generateBoardInfo(id);
} else {
text = self._generateBoardError(id);
}
// No text?
if(!text)
if(!text) {
return false;
}
// Append the content
$('#board').append('<div class="one-board ' + type + '" data-id="' + id + '">' + text + '</div>');
$('#board').append(
'<div class="one-board ' + type + '" data-id="' + id + '">' + text + '</div>'
);
// Events (click and auto-hide)
$('#board .one-board.' + type + '[data-id="' + id + '"]')
.click(function() {
self.closeThis(this);
})
.oneTime('5s', function() {
self.closeThis(this);
})
.slideDown();
self._attachEvents(
$('#board .one-board.' + type + '[data-id="' + id + '"]')
);
return true;
} catch(e) {
@ -235,7 +298,7 @@ var Board = (function () {
try {
// Cannot process?
if(Common.isFocused() || !content || !(window.webkitNotifications || window.Notification)) {
if(Common.isFocused() || !content || !self.NOTIFICATION) {
return;
}
@ -248,11 +311,13 @@ var Board = (function () {
var avatar_xml = Common.XMLFromString(
DataStore.getPersistent('global', 'avatar', xid)
);
var avatar_type = $(avatar_xml).find('type').text() || 'image/png';
var avatar_binval = $(avatar_xml).find('binval').text();
if(avatar_binval && avatar_type)
if(avatar_binval && avatar_type) {
icon = 'data:' + avatar_type + ';base64,' + avatar_binval;
}
}
}
@ -261,8 +326,17 @@ var Board = (function () {
title = Common._e("New event!");
}
// Click callback
var cb_click_fn = function() {
// Create notification
var notification = new self.NOTIFICATION(title, {
dir: 'auto',
lang: '',
body: content,
tag: type,
icon: icon
});
// Click event
notification.onclick = function() {
// Click action?
switch(type) {
case 'chat':
@ -281,53 +355,17 @@ var Board = (function () {
window.focus();
// Remove notification
this.cancel();
this.close();
};
// Check for notification permission
try {
if(Notification.permission == 'granted' || Notification.permission === undefined) {
var notification = new Notification(title, {
dir: 'auto',
lang: '',
body: content,
tag: type,
icon: icon
});
notification.onclick = cb_click_fn;
// Show event
notification.onshow = function() {
setTimeout(function() {
notification.close();
}, 10000);
};
setTimeout(function() {
notification.close();
}, 10000);
if(notification.permission == 'granted') {
return notification;
}
}
} catch(_e) {
if(window.webkitNotifications.checkPermission() === 0) {
// Create notification
var notification = window.webkitNotifications.createNotification(icon, title, content);
// Auto-hide after a while
notification.ondisplay = function(event) {
setTimeout(function() {
event.currentTarget.cancel();
}, 10000);
};
// Click event
notification.onclick = cb_click_fn;
// Show notification
notification.show();
return notification;
}
}
return null;
return notification;
} catch(e) {
Console.error('Board.quick', e);
}
@ -343,21 +381,7 @@ var Board = (function () {
self.quickPermission = function() {
try {
try {
// W3C Notification API (still a draft!)
if(Notification.permission !== 'granted') {
// Ask for permission
Notification.requestPermission();
}
} catch (_e) {
// WebKit Notification API (fallback)
if(!window.webkitNotifications || (window.webkitNotifications.checkPermission() === 0)) {
return;
}
// Ask for permission
window.webkitNotifications.requestPermission();
}
self.NOTIFICATION.requestPermission();
} catch(e) {
Console.error('Board.quickPermission', e);
}
@ -376,8 +400,9 @@ var Board = (function () {
// Fires quickPermission() on document click
$(document).click(function() {
// Ask for permission to use quick boards
if((typeof con != 'undefined') && con.connected())
if((typeof con != 'undefined') && con.connected()) {
self.quickPermission();
}
});
} catch(e) {
Console.error('Board.launch', e);

View file

@ -31,6 +31,7 @@ var Bubble = (function () {
// Destroy all the elements
$('.bubble.hidable:visible').hide();
$('.bubble.removable').remove();
$('body').off('click');
} catch(e) {
Console.error('Bubble.close', e);
@ -53,8 +54,9 @@ var Bubble = (function () {
// Hidable bubbles special things
if($(selector).is('.hidable')) {
// This bubble is yet displayed? So abort!
if($(selector).is(':visible'))
if($(selector).is(':visible')) {
return self.close();
}
// Close all the bubbles
self.close();
@ -66,8 +68,9 @@ var Bubble = (function () {
// Removable bubbles special things
else {
// This bubble is yet added? So abort!
if(Common.exists(selector))
if(Common.exists(selector)) {
return self.close();
}
// Close all the bubbles
self.close();
@ -78,8 +81,9 @@ var Bubble = (function () {
var target = evt.target;
// If this is a click away from a bubble
if(!$(target).parents('.ibubble').size())
if(!$(target).parents('.ibubble').size()) {
self.close();
}
});
} catch(e) {
Console.error('Bubble.show', e);

View file

@ -0,0 +1,972 @@
/*
Jappix - An open social platform
These are the call common management functions
-------------------------------------------------
License: AGPL
Author: Valérian Saliou
*/
// Bundle
var Call = (function() {
/**
* Alias of this
* @private
*/
var self = {};
/* Variables */
self._start_stamp = 0;
/**
* Provides an adapter to the JSJaCJingle console implementation which is different
* @private
* @return {object}
*/
self._consoleAdapter = (function() {
/**
* Alias of this
* @private
*/
var _console = {};
/**
* Console logging interface (adapted)
* @public
* @param {string} message
* @param {number} loglevel
* @return {undefined}
*/
_console.log = function(message, loglevel) {
try {
if(!message) {
throw 'No message passed to console adapter!';
}
switch(loglevel) {
case 0:
Console.warn(message); break;
case 1:
Console.error(message); break;
case 2:
Console.info(message); break;
case 4:
Console.debug(message); break;
default:
Console.log(message);
}
} catch(e) {
Console.error('Call._consoleAdapter.log', e);
}
};
/**
* Return sub-class scope
*/
return _console;
})();
/**
* Initializes Jingle router
* @public
* @return {undefined}
*/
self.init = function() {
try {
// Listen for incoming Jingle/Muji packet
JSJaCJingle.listen({
connection: con,
debug: self._consoleAdapter,
// TODO: setting a fallback fucks up some calls...
// fallback: './server/jingle.php',
single_initiate: function(stanza) {
try {
// Already in a call?
if(self.is_ongoing()) {
// Try to restore SID there
var stanza_id = stanza.getID();
var sid = null;
if(stanza_id) {
var stanza_id_split = stanza_id.split('_');
sid = stanza_id_split[1];
}
// Build a temporary Jingle session
var jingle_close = new JSJaCJingle.session(
JSJAC_JINGLE_SESSION_SINGLE,
{
to: stanza.getFrom(),
debug: JSJaCJingleStorage.get_debug()
}
);
if(sid) {
jingle_close._set_sid(sid);
}
jingle_close.terminate(JSJAC_JINGLE_REASON_BUSY);
Console.warn('session_initiate_success', 'Dropped incoming call because already in a call.');
return;
}
var xid = Common.fullXID(Common.getStanzaFrom(stanza));
Console.info('Incoming call from: ' + xid);
// Session values
Jingle.receive(xid, stanza);
} catch(e) {
Console.error('Call.init[single_initiate]', e);
}
},
// Receive a multiparty (Muji) call
muji_invite: function(stanza, args) {
try {
if(!self.is_ongoing()) {
// Session values
Muji.receive(args, stanza);
}
} catch(e) {
Console.error('Call.init[muji_invite]', e);
}
}
});
// Enable Jingle/Muji UI elements if plugin could start
if(JSJAC_JINGLE_AVAILABLE) {
$('.jingle-hidable, .muji-hidable').show();
}
} catch(e) {
Console.error('Call.init', e);
}
};
/**
* Opens the call interface
* @public
* @return {undefined}
*/
self.open = function() {
try {
if(Jingle.in_call()) {
Jingle.open();
} else if(Muji.in_call()) {
Muji.open();
}
} catch(e) {
Console.error('Call.open', e);
}
};
/**
* Stops current call
* @public
* @return {boolean}
*/
self.stop = function() {
try {
Jingle.stop();
Muji.stop();
} catch(e) {
Console.error('Call.stop', e);
} finally {
return false;
}
};
/**
* Mutes current call
* @public
* @param {object} session
* @param {object} controls
* @return {undefined}
*/
self.mute = function(session, controls) {
try {
if(session) {
// Toggle interface buttons
controls.filter('.mute').hide();
controls.filter('.unmute').show();
// Actually mute audio stream
if(session.get_mute(JSJAC_JINGLE_MEDIA_AUDIO) === false) {
session.mute(JSJAC_JINGLE_MEDIA_AUDIO);
}
}
} catch(e) {
Console.error('Call.mute', e);
}
};
/**
* Unmutes current call
* @public
* @param {object} session
* @param {object} controls
* @return {undefined}
*/
self.unmute = function(session, controls) {
try {
if(session) {
controls.filter('.unmute').hide();
controls.filter('.mute').show();
if(session.get_mute(JSJAC_JINGLE_MEDIA_AUDIO) === true) {
session.unmute(JSJAC_JINGLE_MEDIA_AUDIO);
}
}
} catch(e) {
Console.error('Call.mute', e);
}
};
/**
* Checks whether user is in call or not
* @public
* @return {boolean}
*/
self.is_ongoing = function() {
is_ongoing = false;
try {
is_ongoing = (Jingle.in_call() === true || Muji.in_call() === true);
} catch(e) {
Console.error('Call.is_ongoing', e);
} finally {
return is_ongoing;
}
};
/**
* Checks if the given call SID is the same as the current call's one
* @public
* @param {object} session
* @param {object} compare_session
* @return {boolean}
*/
self.is_same_sid = function(session, compare_session) {
is_same = false;
try {
if(compare_session && session &&
compare_session.get_sid() === session.get_sid()) {
is_same = true;
}
} catch(e) {
Console.error('Call.is_same_sid', e);
} finally {
return is_same;
}
};
/**
* Returns if current call is audio
* @public
* @param {object} session
* @return {boolean}
*/
self.is_audio = function(session) {
audio = false;
try {
if(session && session.get_media() === JSJAC_JINGLE_MEDIA_AUDIO) {
audio = true;
}
} catch(e) {
Console.error('Call.is_audio', e);
} finally {
return audio;
}
};
/**
* Returns if current call is video
* @public
* @param {object} session
* @return {boolean}
*/
self.is_video = function(session) {
video = false;
try {
if(session && session.get_media() === JSJAC_JINGLE_MEDIA_VIDEO) {
video = true;
}
} catch(e) {
Console.error('Call.is_video', e);
} finally {
return video;
}
};
/**
* Set the Muji session as started
* @public
* @param {string} mode
* @return {boolean}
*/
self.start_session = function(mode) {
try {
if(!(mode in JSJAC_JINGLE_MEDIAS)) {
throw 'Unknown mode: ' + (mode || 'none');
}
var call_tool_sel = $('#top-content .tools.call');
call_tool_sel.removeClass('audio video active');
call_tool_sel.addClass('streaming').addClass(mode);
Console.info('Call session successfully started, mode: ' + (mode || 'none'));
} catch(e) {
Console.error('Call.start_session', e);
} finally {
return false;
}
};
/**
* Set the Jingle session as stopped
* @public
* @param {string} mode
* @return {boolean}
*/
self.stop_session = function() {
try {
$('#top-content .tools.call').removeClass('audio video active streaming');
Console.info('Call session successfully stopped');
} catch(e) {
Console.error('Call.stop_session', e);
} finally {
return false;
}
};
/**
* Generates ICE servers configuration
* @public
* @return {object}
*/
self.generate_ice_servers = function() {
ice_servers = {
stun: [],
turn: []
};
try {
if(HOST_STUN) {
ice_servers.stun.push({
'host': HOST_STUN
});
}
if(HOST_TURN) {
ice_servers.turn.push({
'host': HOST_TURN,
'username': HOST_TURN_USERNAME,
'credential': HOST_TURN_PASSWORD
});
}
} catch(e) {
Console.error('Call.generate_ice_servers', e);
} finally {
return is_ongoing;
}
};
/**
* Returns the notification map (based on call type)
* @private
* @param {string} call_type
* @return {object}
*/
self._get_notify_map = function(call_type) {
var map = {};
try {
switch(call_type) {
case JSJAC_JINGLE_SESSION_SINGLE:
map = Jingle._notify_map(); break;
case JSJAC_JINGLE_SESSION_MUJI:
map = Muji._notify_map(); break;
default:
return;
}
} catch(e) {
Console.error('Call._get_notify_map', e);
} finally {
return map;
}
};
/**
* Notify for something related to calls
* @public
* @param {string} call_type
* @param {string} xid
* @param {string} type
* @param {string} mode
* @return {boolean}
*/
self.notify = function(call_type, xid, type, mode, sender_xid) {
try {
sender_xid = sender_xid || xid;
// Notification data map
var map = self._get_notify_map(call_type);
if(!(type in map)) {
throw 'Notification type not recognized!';
}
// Selectors
var call_tools_all_sel = $('#top-content .tools-all:has(.tools.call)');
var call_tool_sel = call_tools_all_sel.find('.tools.call');
var call_content_sel = call_tools_all_sel.find('.call-content');
var call_subitem_sel = call_content_sel.find('.tools-content-subitem');
// Generate proper full name
var fullname;
if(call_type === JSJAC_JINGLE_SESSION_MUJI && sender_xid === Common.getXID()) {
fullname = Common._e("Conference call");
} else {
fullname = Name.getBuddy(sender_xid).htmlEnc();
}
// Generate buttons code
var buttons_html = '';
var i = 0;
if(typeof map[type].buttons === 'object') {
$.each(map[type].buttons, function(button, attrs) {
buttons_html += '<a class="reply-button ' + button + ' ' + attrs.color + ' ' + (!(i++) ? 'first' : '') + '" data-action="' + button + '">' + attrs.text + '</a>';
});
}
// Append notification to DOM
call_subitem_sel.html(
'<div class="call-notify notify-' + type + ' ' + hex_md5(sender_xid) + '" data-type="' + type + '" data-xid="' + Common.encodeQuotes(xid) + '">' +
'<div class="avatar-pane">' +
'<div class="avatar-container">' +
'<img class="avatar" src="' + './images/others/default-avatar.png' + '" alt="" />' +
'</div>' +
'<span class="icon call-images"></span>' +
'</div>' +
'<div class="notification-content">' +
'<span class="fullname">' + fullname + '</span>' +
'<span class="text">' + map[type].text + '</span>' +
'<div class="reply-buttons">' + buttons_html + '</div>' +
'</div>' +
'</div>'
);
// Apply user avatar
Avatar.get(sender_xid, 'cache', 'true', 'forget');
// Apply button events
if(typeof map[type].buttons === 'object') {
$.each(map[type].buttons, function(button, attrs) {
call_tools_all_sel.find('a.reply-button[data-action="' + button + '"]').click(function() {
try {
// Remove notification
self._unnotify(xid);
// Execute callback, if any
if(typeof attrs.cb === 'function') {
attrs.cb(xid, mode);
}
Console.info('Closed call notification drawer');
} catch(e) {
Console.error('Call.notify[async]', e);
} finally {
return false;
}
});
});
}
// Enable notification box!
call_tool_sel.addClass('active');
// Open notification box!
call_content_sel.show();
} catch(e) {
Console.error('Call.notify', e);
} finally {
return false;
}
};
/**
* Remove notification
* @private
* @return {boolean}
*/
self._unnotify = function() {
try {
// Selectors
var call_tools_all_sel = $('#top-content .tools-all:has(.tools.call)');
var call_tool_sel = call_tools_all_sel.find('.tools.call');
var call_content_sel = call_tools_all_sel.find('.call-content');
var call_subitem_sel = call_content_sel.find('.tools-content-subitem');
// Close & disable notification box
call_content_sel.hide();
call_subitem_sel.empty();
call_tool_sel.removeClass('active');
// Stop all sounds
Audio.stop('incoming-call');
Audio.stop('outgoing-call');
} catch(e) {
Console.error('Call._unnotify', e);
} finally {
return false;
}
};
/**
* Processes the video elements size
* @private
* @param {object} screen
* @param {object} video
* @return {object}
*/
self._process_size = function(screen, video) {
try {
if(!(typeof screen === 'object' && typeof video === 'object')) {
throw 'Invalid object passed, aborting!';
}
// Get the intrinsic size of the video
var video_w = video[0].videoWidth || video.width();
var video_h = video[0].videoHeight || video.height();
// Get the screen size of the video
var screen_w = screen.width();
var screen_h = screen.height();
// Process resize ratios (2 cases)
var r_1 = screen_h / video_h;
var r_2 = screen_w / video_w;
// Process resized video sizes
var video_w_1 = video_w * r_1;
var video_h_1 = video_h * r_1;
var video_w_2 = video_w * r_2;
var video_h_2 = video_h * r_2;
// DOM view modifiers
var dom_width = 'auto';
var dom_height = 'auto';
var dom_left = 0;
var dom_top = 0;
// Landscape/Portrait/Equal container?
if(video_w > video_h || (video_h == video_w && screen_w < screen_h)) {
// Not sufficient?
if(video_w_1 < screen_w) {
dom_width = screen_w + 'px';
dom_top = -1 * (video_h_2 - screen_h) / 2;
} else {
dom_height = screen_h + 'px';
dom_left = -1 * (video_w_1 - screen_w) / 2;
}
} else if(video_h > video_w || (video_h == video_w && screen_w > screen_h)) {
// Not sufficient?
if(video_h_1 < screen_h) {
dom_height = screen_h + 'px';
dom_left = -1 * (video_w_1 - screen_w) / 2;
} else {
dom_width = screen_w + 'px';
dom_top = -1 * (video_h_2 - screen_h) / 2;
}
} else if(screen_w == screen_h) {
dom_width = screen_w + 'px';
dom_height = screen_h + 'px';
}
return {
width : dom_width,
height : dom_height,
left : dom_left,
top : dom_top
};
} catch(e) {
Console.error('Call._process_size', e);
}
};
/**
* Adapts the local video view
* @public
* @param {object} local_sel
* @return {undefined}
*/
self.adapt_local = function(local_sel) {
try {
var local_video_sel = local_sel.find('video');
// Process new sizes
var sizes = Call._process_size(
local_sel,
local_video_sel
);
// Apply new sizes
local_video_sel.css({
'height': sizes.height,
'width': sizes.width,
'margin-top': sizes.top,
'margin-left': sizes.left
});
} catch(e) {
Console.error('Call.adapt_local', e);
}
};
/**
* Adapts the remote video view
* @public
* @param {object} videobox_sel
* @return {undefined}
*/
self.adapt_remote = function(videobox_sel) {
try {
var remote_video_sel, sizes;
videobox_sel.find('.remote_video').each(function() {
remote_video_sel = $(this).find('video');
if(remote_video_sel.size()) {
// Process new sizes
sizes = Call._process_size(
$(this),
remote_video_sel
);
// Apply new sizes
remote_video_sel.css({
'height': sizes.height,
'width': sizes.width,
'margin-top': sizes.top,
'margin-left': sizes.left
});
}
});
} catch(e) {
Console.error('Call.adapt_remote', e);
}
};
/**
* Start call elpsed time counter
* @public
* @return {boolean}
*/
self.start_counter = function() {
try {
// Initialize counter
self.stop_counter();
self._start_stamp = DateUtils.getTimeStamp();
self._fire_clock();
// Fire it every second
$('#top-content .tools.call .counter').everyTime('1s', self._fire_clock);
Console.info('Call counter started');
} catch(e) {
Console.error('Call.start_counter', e);
} finally {
return false;
}
};
/**
* Stop call elpsed time counter
* @public
* @return {boolean}
*/
self.stop_counter = function() {
try {
// Reset stamp storage
self._start_stamp = 0;
// Reset counter
var counter_sel = $('#top-content .tools.call .counter');
var default_count = counter_sel.attr('data-default');
counter_sel.stopTime();
$('#top-content .tools.call .counter').text(default_count);
$('#jingle, #muji').find('.elapsed').text(default_count);
Console.info('Call counter stopped');
} catch(e) {
Console.error('Call.stop_counter', e);
} finally {
return false;
}
};
/**
* Fires the counter clock (once more)
* @private
* @return {undefined}
*/
self._fire_clock = function() {
try {
// Process updated time
var count = DateUtils.difference(
DateUtils.getTimeStamp(),
self._start_stamp
);
if(count.getHours()) {
count = count.toString('H:mm:ss');
} else {
count = count.toString('mm:ss');
}
// Display updated counter
$('#top-content .tools.call .counter').text(count);
$('#jingle, #muji').find('.elapsed').text(count);
} catch(e) {
Console.error('Call._fire_clock', e);
}
};
/**
* Destroy the call interface
* @public
* @return {undefined}
*/
self.destroy_interface = function(container_sel) {
try {
container_sel.stopTime();
container_sel.find('*').stopTime();
container_sel.remove();
} catch(e) {
Console.error('Call.destroy_interface', e);
}
};
/**
* Show the call interface
* @public
* @param {object} manager
* @param {object} call_sel
* @param {object} video_container_sel
* @return {boolean}
*/
self.show_interface = function(manager, call_sel, video_container_sel) {
try {
if(manager.in_call()) {
call_sel.filter(':hidden').show();
// Launch back some events
video_container_sel.mousemove();
}
} catch(e) {
Console.error('Call.show_interface', e);
} finally {
return false;
}
};
/**
* Hide the call interface
* @public
* @param {object} call_sel
* @param {object} video_container_sel
* @return {boolean}
*/
self.hide_interface = function(call_sel, video_container_sel) {
try {
call_sel.filter(':visible').hide();
// Reset some events
video_container_sel.find('.topbar').stopTime().hide();
} catch(e) {
Console.error('Call.hide_interface', e);
} finally {
return false;
}
};
/**
* Attaches interface events
* @public
* @param {object} manager
* @param {object} call_sel
* @param {object} video_container_sel
* @return {undefined}
*/
self.events_interface = function(manager, call_sel, video_container_sel) {
try {
call_sel.everyTime(50, function() {
manager._adapt();
});
// Close interface on click on semi-transparent background
call_sel.click(function(evt) {
try {
// Click on lock background?
if($(evt.target).is('.lock')) {
return manager._hide_interface();
}
} catch(e) {
Console.error('Call.events_interface[async]', e);
}
});
// Click on a control or action button
call_sel.find('.topbar').find('.controls a, .actions a').click(function() {
try {
switch($(this).data('type')) {
case 'close':
manager._hide_interface(); break;
case 'stop':
case 'leave':
manager.stop(); break;
case 'mute':
manager.mute(); break;
case 'unmute':
manager.unmute(); break;
}
} catch(e) {
Console.error('Call.events_interface[async]', e);
} finally {
return false;
}
});
// Auto Hide/Show interface topbar
video_container_sel.mousemove(function() {
try {
var topbar_sel = $(this).find('.topbar');
if(topbar_sel.is(':hidden')) {
topbar_sel.stop(true).fadeIn(250);
}
topbar_sel.stopTime();
topbar_sel.oneTime('5s', function() {
topbar_sel.stop(true).fadeOut(250);
});
} catch(e) {
Console.error('Call.events_interface[async]', e);
}
});
} catch(e) {
Console.error('Call.events_interface', e);
}
};
/**
* Return class scope
*/
return self;
})();

View file

@ -20,6 +20,444 @@ var Caps = (function () {
var self = {};
/* Constants */
self.disco_infos = {
'identity': {
'category': 'client',
'type': 'web',
'name': 'Jappix'
},
'items': [
NS_MUC,
NS_MUC_USER,
NS_MUC_ADMIN,
NS_MUC_OWNER,
NS_MUC_CONFIG,
NS_DISCO_INFO,
NS_DISCO_ITEMS,
NS_PUBSUB_RI,
NS_BOSH,
NS_CAPS,
NS_MOOD,
NS_ACTIVITY,
NS_TUNE,
NS_GEOLOC,
NS_NICK,
NS_URN_MBLOG,
NS_URN_INBOX,
NS_MOOD + NS_NOTIFY,
NS_ACTIVITY + NS_NOTIFY,
NS_TUNE + NS_NOTIFY,
NS_GEOLOC + NS_NOTIFY,
NS_URN_MBLOG + NS_NOTIFY,
NS_URN_INBOX + NS_NOTIFY,
NS_URN_DELAY,
NS_ROSTER,
NS_ROSTERX,
NS_HTTP_AUTH,
NS_CHATSTATES,
NS_XHTML_IM,
NS_URN_MAM,
NS_IPV6,
NS_LAST,
NS_PRIVATE,
NS_REGISTER,
NS_SEARCH,
NS_COMMANDS,
NS_VERSION,
NS_XDATA,
NS_VCARD,
NS_IETF_VCARD4,
NS_URN_ADATA,
NS_URN_AMETA,
NS_URN_TIME,
NS_URN_PING,
NS_URN_RECEIPTS,
NS_PRIVACY,
NS_IQOOB,
NS_XOOB,
NS_URN_CARBONS,
NS_URN_CORRECT,
NS_URN_MARKERS,
NS_URN_IDLE,
NS_URN_ATTENTION,
NS_URN_REACH,
NS_URN_HINTS
]
};
/**
* Parse identities from disco infos query response
* @private
* @param {object} query
* @return {object}
*/
self._parseDiscoIdentities = function(query) {
var identities = [];
try {
var cur_category, cur_type, cur_lang, cur_name;
$(query).find('identity').each(function() {
cur_category = $(this).attr('category') || '';
cur_type = $(this).attr('type') || '';
cur_lang = $(this).attr('xml:lang') || '';
cur_name = $(this).attr('name') || '';
identities.push(cur_category + '/' + cur_type + '/' + cur_lang + '/' + cur_name);
});
} catch(e) {
Console.error('Caps._parseDiscoIdentities', e);
} finally {
return identities;
}
};
/**
* Parse features from disco infos query response
* @private
* @param {object} query
* @return {object}
*/
self._parseDiscoFeatures = function(query) {
var features = [];
try {
var cur_var;
$(query).find('feature').each(function() {
cur_var = $(this).attr('var');
// Add the current value to the array
if(cur_var) {
features.push(cur_var);
}
});
} catch(e) {
Console.error('Caps._parseDiscoFatures', e);
} finally {
return features;
}
};
/**
* Parse data form from disco infos query response
* @private
* @param {object} query
* @return {object}
*/
self._parseDiscoDataForms = function(query) {
var data_forms = [];
try {
var cur_string, cur_sort_var,
cur_text, cur_var, cur_sort_val;
$(query).find('x[xmlns="' + NS_XDATA + '"]').each(function() {
// Initialize some stuffs
cur_string = '';
cur_sort_var = [];
// Add the form type field
$(this).find('field[var="FORM_TYPE"] value').each(function() {
cur_text = $(this).text();
if(cur_text) {
cur_string += cur_text + '<';
}
});
// Add the var attributes into an array
$(this).find('field:not([var="FORM_TYPE"])').each(function() {
cur_var = $(this).attr('var');
if(cur_var) {
cur_sort_var.push(cur_var);
}
});
// Sort the var attributes
cur_sort_var = cur_sort_var.sort();
// Loop this sorted var attributes
$.each(cur_sort_var, function(i) {
// Initialize the value sorting
cur_sort_val = [];
// Append it to the string
cur_string += cur_sort_var[i] + '<';
// Add each value to the array
$(this).find('field[var=' + cur_sort_var[i] + '] value').each(function() {
cur_sort_val.push($(this).text());
});
// Sort the values
cur_sort_val = cur_sort_val.sort();
// Append the values to the string
for(var j in cur_sort_val) {
cur_string += cur_sort_val[j] + '<';
}
});
// Any string?
if(cur_string) {
// Remove the undesired double '<' from the string
if(cur_string.match(/(.+)(<)+$/)) {
cur_string = cur_string.substring(0, cur_string.length - 1);
}
// Add the current string to the array
data_forms.push(cur_string);
}
});
} catch(e) {
Console.error('Caps._parseDiscoDataForms', e);
} finally {
return data_forms;
}
};
/**
* Apply XHTML-IM features from disco infos
* @private
* @param {string} xid
* @param {object} features
* @param {object} style_sel
* @param {object} message_area_sel
* @return {undefined}
*/
self._applyDiscoXHTMLIM = function(xid, features, style_sel, message_area_sel) {
try {
// Apply
if(NS_XHTML_IM in features) {
style_sel.show();
} else {
// Remove the tooltip elements
style_sel.hide();
style_sel.find('.bubble-style').remove();
// Reset the markers
message_area_sel.removeAttr('style')
.removeAttr('data-font')
.removeAttr('data-fontsize')
.removeAttr('data-color')
.removeAttr('data-bold')
.removeAttr('data-italic')
.removeAttr('data-underline');
}
} catch(e) {
Console.error('Caps._applyDiscoXHTMLIM', e);
}
};
/**
* Apply Jingle features from disco infos
* @private
* @param {string} xid
* @param {object} path_sel
* @param {object} roster_sel
* @return {undefined}
*/
self._applyDiscoJingle = function(xid, path_sel, roster_sel) {
try {
// Selectors
var roster_jingle_sel = roster_sel.find('.buddy-infos .call-jingle');
var jingle_audio = path_sel.find('.tools-jingle-audio');
var roster_jingle_audio = roster_jingle_sel.find('a.audio');
var jingle_video = path_sel.find('.tools-jingle-video');
var roster_jingle_video = roster_jingle_sel.find('a.video');
var roster_jingle_separator = roster_jingle_sel.find('span.separator');
// Apply
var jingle_local_supported = JSJAC_JINGLE_AVAILABLE;
var jingle_audio_xid = self.getFeatureResource(xid, NS_JINGLE_APPS_RTP_AUDIO);
var jingle_video_xid = self.getFeatureResource(xid, NS_JINGLE_APPS_RTP_VIDEO);
if(jingle_audio_xid && jingle_local_supported) {
jingle_audio.show();
roster_jingle_audio.show();
} else {
jingle_audio.hide();
roster_jingle_audio.hide();
}
if(jingle_video_xid && jingle_local_supported) {
jingle_video.show();
roster_jingle_video.show();
} else {
jingle_video.hide();
roster_jingle_video.hide();
}
if(jingle_audio_xid && jingle_video_xid && jingle_local_supported) {
roster_jingle_separator.show();
} else {
roster_jingle_separator.hide();
}
if((jingle_audio_xid || jingle_video_xid) && jingle_local_supported) {
roster_jingle_sel.show();
} else {
roster_jingle_sel.hide();
}
} catch(e) {
Console.error('Caps._applyDiscoJingle', e);
}
};
/**
* Apply Out of Band Data features from disco infos
* @private
* @param {string} xid
* @param {object} features
* @param {object} file_sel
* @return {undefined}
*/
self._applyDiscoOOB = function(xid, features, file_sel) {
try {
// Apply
var iq_oob_xid = self.getFeatureResource(xid, NS_IQOOB);
if(iq_oob_xid || NS_XOOB in features) {
file_sel.show();
// Set a marker
file_sel.attr(
'data-oob',
iq_oob_xid ? 'iq' : 'x'
);
} else {
// Remove the tooltip elements
file_sel.hide();
file_sel.find('.bubble-style').remove();
// Reset the marker
file_sel.removeAttr('data-oob');
}
} catch(e) {
Console.error('Caps._applyDiscoOOB', e);
}
};
/**
* Apply Receipts features from disco infos
* @private
* @param {string} xid
* @param {object} features
* @param {object} message_area_sel
* @return {undefined}
*/
self._applyDiscoReceipts = function(xid, features, message_area_sel) {
try {
// Apply
if(NS_URN_RECEIPTS in features) {
message_area_sel.attr('data-receipts', 'true');
} else {
message_area_sel.removeAttr('data-receipts');
}
} catch(e) {
Console.error('Caps._applyDiscoReceipts', e);
}
};
/**
* Apply Last Message Correction features from disco infos
* @private
* @param {string} xid
* @param {object} features
* @param {object} path_sel
* @return {undefined}
*/
self._applyDiscoCorrection = function(xid, features, path_sel) {
try {
// Apply
if(NS_URN_CORRECT in features) {
path_sel.attr('data-correction', 'true');
} else {
path_sel.removeAttr('data-correction');
}
} catch(e) {
Console.error('Caps._applyDiscoCorrection', e);
}
};
/**
* Apply Chat Markers features from disco infos
* @private
* @param {string} xid
* @param {object} features
* @param {object} path_sel
* @return {undefined}
*/
self._applyDiscoMarkers = function(xid, features, path_sel) {
try {
// Apply
if(NS_URN_MARKERS in features) {
path_sel.attr('data-markers', 'true');
} else {
path_sel.removeAttr('data-markers');
}
} catch(e) {
Console.error('Caps._applyDiscoMarkers', e);
}
};
/**
* Apply Attention features from disco infos
* @private
* @param {string} xid
* @param {object} features
* @param {object} path_sel
* @return {undefined}
*/
self._applyDiscoAttention = function(xid, features, path_sel) {
try {
// Apply
if(NS_URN_ATTENTION in features) {
path_sel.attr('data-attention', 'true');
} else {
path_sel.removeAttr('data-attention');
}
} catch(e) {
Console.error('Caps._applyDiscoAttention', e);
}
};
/**
* Reads a stored Caps
* @public
@ -47,62 +485,12 @@ var Caps = (function () {
self.myDiscoInfos = function() {
try {
var disco_base = [
NS_MUC,
NS_MUC_USER,
NS_MUC_ADMIN,
NS_MUC_OWNER,
NS_MUC_CONFIG,
NS_DISCO_INFO,
NS_DISCO_ITEMS,
NS_PUBSUB_RI,
NS_BOSH,
NS_CAPS,
NS_MOOD,
NS_ACTIVITY,
NS_TUNE,
NS_GEOLOC,
NS_NICK,
NS_URN_MBLOG,
NS_URN_INBOX,
NS_MOOD + NS_NOTIFY,
NS_ACTIVITY + NS_NOTIFY,
NS_TUNE + NS_NOTIFY,
NS_GEOLOC + NS_NOTIFY,
NS_URN_MBLOG + NS_NOTIFY,
NS_URN_INBOX + NS_NOTIFY,
NS_URN_DELAY,
NS_ROSTER,
NS_ROSTERX,
NS_HTTP_AUTH,
NS_CHATSTATES,
NS_XHTML_IM,
NS_URN_MAM,
NS_IPV6,
NS_LAST,
NS_PRIVATE,
NS_REGISTER,
NS_SEARCH,
NS_COMMANDS,
NS_VERSION,
NS_XDATA,
NS_VCARD,
NS_IETF_VCARD4,
NS_URN_ADATA,
NS_URN_AMETA,
NS_URN_TIME,
NS_URN_PING,
NS_URN_RECEIPTS,
NS_PRIVACY,
NS_IQOOB,
NS_XOOB,
NS_URN_CARBONS
];
var disco_base = self.disco_infos.items;
var disco_jingle = JSJaCJingle_disco();
var disco_jingle = JSJaCJingle.disco();
var disco_all = disco_base.concat(disco_jingle);
return disco_all;
return Utils.uniqueArrayValues(disco_all);
} catch(e) {
Console.error('Caps.myDiscoInfos', e);
}
@ -169,103 +557,17 @@ var Caps = (function () {
self.handleDiscoInfos = function(iq) {
try {
if(!iq || (iq.getType() == 'error'))
if(!iq || (iq.getType() == 'error')) {
return;
}
// IQ received, get some values
var from = Common.fullXID(Common.getStanzaFrom(iq));
var query = iq.getQuery();
// Generate the CAPS-processing values
var identities = [];
var features = [];
var data_forms = [];
// Identity values
$(query).find('identity').each(function() {
var pCategory = $(this).attr('category');
var pType = $(this).attr('type');
var pLang = $(this).attr('xml:lang');
var pName = $(this).attr('name');
if(!pCategory)
pCategory = '';
if(!pType)
pType = '';
if(!pLang)
pLang = '';
if(!pName)
pName = '';
identities.push(pCategory + '/' + pType + '/' + pLang + '/' + pName);
});
// Feature values
$(query).find('feature').each(function() {
var pVar = $(this).attr('var');
// Add the current value to the array
if(pVar)
features.push(pVar);
});
// Data-form values
$(query).find('x[xmlns="' + NS_XDATA + '"]').each(function() {
// Initialize some stuffs
var pString = '';
var sortVar = [];
// Add the form type field
$(this).find('field[var="FORM_TYPE"] value').each(function() {
var cText = $(this).text();
if(cText)
pString += cText + '<';
});
// Add the var attributes into an array
$(this).find('field:not([var="FORM_TYPE"])').each(function() {
var cVar = $(this).attr('var');
if(cVar)
sortVar.push(cVar);
});
// Sort the var attributes
sortVar = sortVar.sort();
// Loop this sorted var attributes
$.each(sortVar, function(i) {
// Initialize the value sorting
var sortVal = [];
// Append it to the string
pString += sortVar[i] + '<';
// Add each value to the array
$(this).find('field[var=' + sortVar[i] + '] value').each(function() {
sortVal.push($(this).text());
});
// Sort the values
sortVal = sortVal.sort();
// Append the values to the string
for(var j in sortVal) {
pString += sortVal[j] + '<';
}
});
// Any string?
if(pString) {
// Remove the undesired double '<' from the string
if(pString.match(/(.+)(<)+$/))
pString = pString.substring(0, pString.length - 1);
// Add the current string to the array
data_forms.push(pString);
}
});
// Parse values
var identities = self._parseDiscoIdentities(query);
var features = self._parseDiscoFeatures(query);
var data_forms = self._parseDiscoDataForms(query);
// Process the CAPS
var caps = self.process(identities, features, data_forms);
@ -309,8 +611,9 @@ var Caps = (function () {
var xid = Common.bareXID(from);
// This comes from a private groupchat chat?
if(Utils.isPrivate(xid))
if(Utils.isPrivate(xid)) {
xid = from;
}
hash = hex_md5(xid);
@ -326,96 +629,20 @@ var Caps = (function () {
});
// Paths
var path = $('#' + hash);
var roster_path = $('#roster .buddy.' + hash);
var roster_jingle_path = roster_path.find('.buddy-infos .call-jingle');
var message_area = path.find('.message-area');
var style = path.find('.chat-tools-style');
var jingle_audio = path.find('.tools-jingle-audio');
var roster_jingle_audio = roster_jingle_path.find('a.audio');
var jingle_video = path.find('.tools-jingle-video');
var roster_jingle_video = roster_jingle_path.find('a.video');
var roster_jingle_separator = roster_jingle_path.find('span.separator');
var file = path.find('.chat-tools-file');
var path_sel = $('#' + hash);
var roster_sel = $('#roster .buddy.' + hash);
var message_area_sel = path_sel.find('.message-area');
var style_sel = path_sel.find('.chat-tools-style');
var file_sel = path_sel.find('.chat-tools-file');
// Apply xHTML-IM
if(NS_XHTML_IM in features) {
style.show();
} else {
// Remove the tooltip elements
style.hide();
style.find('.bubble-style').remove();
// Reset the markers
message_area.removeAttr('style')
.removeAttr('data-font')
.removeAttr('data-fontsize')
.removeAttr('data-color')
.removeAttr('data-bold')
.removeAttr('data-italic')
.removeAttr('data-underline');
}
// Apply Jingle
var jingle_local_supported = JSJAC_JINGLE_AVAILABLE;
var jingle_audio_xid = self.getFeatureResource(xid, NS_JINGLE_APPS_RTP_AUDIO);
var jingle_video_xid = self.getFeatureResource(xid, NS_JINGLE_APPS_RTP_VIDEO);
if(jingle_audio_xid && jingle_local_supported) {
jingle_audio.show();
roster_jingle_audio.show();
} else {
jingle_audio.hide();
roster_jingle_audio.hide();
}
if(jingle_video_xid && jingle_local_supported) {
jingle_video.show();
roster_jingle_video.show();
} else {
jingle_video.hide();
roster_jingle_video.hide();
}
if(jingle_audio_xid && jingle_video_xid && jingle_local_supported) {
roster_jingle_separator.show();
} else {
roster_jingle_separator.hide();
}
if((jingle_audio_xid || jingle_video_xid) && jingle_local_supported) {
roster_jingle_path.show();
} else {
roster_jingle_path.hide();
}
// Apply Out of Band Data
var iq_oob_xid = self.getFeatureResource(xid, NS_IQOOB);
if(iq_oob_xid || NS_XOOB in features) {
file.show();
// Set a marker
file.attr(
'data-oob',
iq_oob_xid ? 'iq' : 'x'
);
} else {
// Remove the tooltip elements
file.hide();
file.find('.bubble-style').remove();
// Reset the marker
file.removeAttr('data-oob');
}
// Apply receipts
if(NS_URN_RECEIPTS in features) {
message_area.attr('data-receipts', 'true');
} else {
message_area.removeAttr('data-receipts');
}
// Apply Features
self._applyDiscoXHTMLIM(xid, features, style_sel, message_area_sel);
self._applyDiscoJingle(xid, path_sel, roster_sel);
self._applyDiscoOOB(xid, features, file_sel);
self._applyDiscoReceipts(xid, features, message_area_sel);
self._applyDiscoCorrection(xid, features, path_sel);
self._applyDiscoMarkers(xid, features, path_sel);
self._applyDiscoAttention(xid, features, path_sel);
} catch(e) {
Console.error('Caps.displayDiscoInfos', e);
}
@ -426,39 +653,39 @@ var Caps = (function () {
/**
* Generates the CAPS hash
* @public
* @param {object} cIdentities
* @param {object} cFeatures
* @param {object} cDataForms
* @param {object} identities
* @param {object} features
* @param {object} dataforms
* @return {string}
*/
self.process = function(cIdentities, cFeatures, cDataForms) {
self.process = function(identities, features, dataforms) {
try {
// Initialize
var cString = '';
var caps_str = '';
// Sort the arrays
cIdentities = cIdentities.sort();
cFeatures = cFeatures.sort();
cDataForms = cDataForms.sort();
identities = identities.sort();
features = features.sort();
dataforms = dataforms.sort();
// Process the sorted identity string
for(var a in cIdentities) {
cString += cIdentities[a] + '<';
for(var a in identities) {
caps_str += identities[a] + '<';
}
// Process the sorted feature string
for(var b in cFeatures) {
cString += cFeatures[b] + '<';
for(var b in features) {
caps_str += features[b] + '<';
}
// Process the sorted data-form string
for(var c in cDataForms) {
cString += cDataForms[c] + '<';
for(var c in dataforms) {
caps_str += dataforms[c] + '<';
}
// Process the SHA-1 hash
var cHash = b64_sha1(cString);
var cHash = b64_sha1(caps_str);
return cHash;
} catch(e) {
@ -477,7 +704,12 @@ var Caps = (function () {
try {
return self.process(
['client/web//Jappix'],
[
self.disco_infos.identity.category + '/' +
self.disco_infos.identity.type + '//' +
self.disco_infos.identity.name
],
self.myDiscoInfos(),
[]
);
@ -507,8 +739,14 @@ var Caps = (function () {
var max_priority = null;
var cur_xid_full, cur_presence_sel, cur_caps, cur_features, cur_priority;
for(var cur_resource in Presence.resources(xid)) {
cur_xid_full = xid + '/' + cur_resource;
var resources_obj = Presence.resources(xid);
var fn_parse_resource = function(cur_resource) {
cur_xid_full = xid;
if(cur_resource) {
cur_xid_full += '/' + cur_resource;
}
cur_presence_sel = $(Presence.readStanza(cur_xid_full));
cur_priority = parseInt((cur_presence_sel.find('priority').text() || 0), 10);
@ -523,6 +761,14 @@ var Caps = (function () {
selected_xid = cur_xid_full;
}
}
};
if(resources_obj.bare === 1) {
fn_parse_resource(null);
}
for(var cur_resource in resources_obj.list) {
fn_parse_resource(cur_resource);
}
} catch(e) {
Console.error('Caps.getFeatureResource', e);
@ -538,4 +784,4 @@ var Caps = (function () {
*/
return self;
})();
})();

View file

@ -22,7 +22,7 @@ var Carbons = (function () {
/**
* Configures Message Carbons options
* @public
* @private
* @param {string} type
* @return {undefined}
*/
@ -50,7 +50,7 @@ var Carbons = (function () {
/**
* Configures Message Carbons options
* @public
* @private
* @param {object} iq
* @param {string} type
* @return {undefined}
@ -193,6 +193,9 @@ var Carbons = (function () {
} else {
Console.debug('Got a sent message from another resource to: ' + (to || 'none') + ', was ignored because body empty');
}
// Handle chat markers change
Markers.handleCarbonChange(forwarded_message);
} else {
Console.debug('Got a sent message from another resource to: ' + (to || 'none') + ', was ignored because chat not open');
}

View file

@ -20,6 +20,289 @@ var Chat = (function () {
var self = {};
/**
* Apply generate events
* @private
* @param {string} path
* @param {string} id
* @param {string} xid
* @return {undefined}
*/
self._generateEvents = function(path, id, xid) {
try {
// Click event: chat cleaner
$(path + 'tools-clear').click(function() {
self.clean(id);
});
// Click event: call (audio)
$(path + 'tools-jingle-audio').click(function() {
Jingle.start(xid, 'audio');
});
// Click event: call (video)
$(path + 'tools-jingle-video').click(function() {
Jingle.start(xid, 'video');
});
// Click event: user-infos
$(path + 'tools-infos').click(function() {
UserInfos.open(xid);
});
} catch(e) {
Console.error('Chat._generateEvents', e);
}
};
/**
* Apply generate events
* @private
* @param {object} input_sel
* @param {string} xid
* @param {string} hash
* @return {undefined}
*/
self._createEvents = function(input_sel, xid, hash) {
try {
self._createEventsInput(input_sel, hash);
self._createEventsKey(input_sel, xid, hash);
self._createEventsMouse(xid, hash);
} catch(e) {
Console.error('Chat._createEvents', e);
}
};
/**
* Apply generate events (input)
* @private
* @param {object} input_sel
* @param {string} hash
* @return {undefined}
*/
self._createEventsInput = function(input_sel, hash) {
try {
input_sel.focus(function() {
// Clean notifications for this chat
Interface.chanCleanNotify(hash);
// Store focus on this chat!
Interface.chat_focus_hash = hash;
});
input_sel.blur(function() {
// Reset storage about focus on this chat!
if(Interface.chat_focus_hash == hash) {
Interface.chat_focus_hash = null;
}
});
} catch(e) {
Console.error('Chat._createEventsInput', e);
}
};
/**
* Apply generate events (key)
* @private
* @param {object} input_sel
* @param {string} xid
* @param {string} hash
* @return {undefined}
*/
self._createEventsKey = function(input_sel, xid, hash) {
try {
input_sel.keydown(function(e) {
if(e.keyCode == 13) {
// Enter key
if(e.shiftKey || e.ctrlKey) {
// Add a new line
input_sel.val(input_sel.val() + '\n');
} else {
if(Correction.isIn(xid) === true) {
var corrected_value = input_sel.val().trim();
if(corrected_value) {
// Send the corrected message
Correction.send(xid, 'chat', corrected_value);
}
Correction.leave(xid);
} else {
// Send the message
Message.send(hash, 'chat');
}
// Reset the composing database entry
DataStore.setDB(Connection.desktop_hash, 'chatstate', xid, 'off');
}
return false;
} else if(e.keyCode == 8) {
// Leave correction mode? (another way, by flushing input value progressively)
if(Correction.isIn(xid) === true && !input_sel.val()) {
Correction.leave(xid);
}
}
});
input_sel.keyup(function(e) {
if(e.keyCode == 27) {
// Escape key
input_sel.val('');
// Leave correction mode? (simple escape way)
if(Correction.isIn(xid) === true) {
Correction.leave(xid);
}
} else {
Correction.detect(xid, input_sel);
}
});
} catch(e) {
Console.error('Chat._createEventsKey', e);
}
};
/**
* Apply generate events (mouse)
* @private
* @param {string} xid
* @param {string} hash
* @return {undefined}
*/
self._createEventsMouse = function(xid, hash) {
try {
// 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);
}
});
}
}
});
} catch(e) {
Console.error('Chat._createEventsMouse', e);
}
};
/**
* Apply generate events
* @private
* @param {string} type
* @param {string} id
* @return {object}
*/
self._generateChatCode = function(type, id) {
var code_args = {};
try {
// Groupchat special code
if(type == 'groupchat') {
code_args.attributes = ' data-type="groupchat" data-correction="true"';
code_args.avatar = '';
code_args.name = '<p class="bc-infos"><b>' + Common._e("Subject") + '</b> <span class="muc-topic">' + Common._e("no subject defined for this room.") + '</span></p>';
code_args.code = '<div class="content groupchat-content" id="chat-content-' + id + '"></div>' +
'<div class="list"><div class="moderator role"><p class="title">' + Common._e("Moderators") + '</p></div>' +
'<div class="participant role"><p class="title">' + Common._e("Participants") + '</p></div>' +
'<div class="visitor role"><p class="title">' + Common._e("Visitors") + '</p></div>' +
'<div class="none role"><p class="title">' + Common._e("Others") + '</p></div></div>';
code_args.link = '<a href="#" class="tools-mucadmin tools-tooltip talk-images chat-tools-content" title="' + Common._e("Administration panel for this room") + '"></a>';
code_args.style = '';
// Is this a gateway?
if(xid.match(/%/)) {
code_args.disabled = '';
} else {
code_args.disabled = ' disabled=""';
}
} else {
code_args.mam = '<div class="wait-mam wait-small"></div>';
code_args.attributes = ' data-type="chat"';
code_args.avatar = '<div class="avatar-container"><img class="avatar" src="' + './images/others/default-avatar.png' + '" alt="" /></div>';
code_args.name = '<div class="bc-pep"></div><p class="bc-infos"><span class="unavailable show talk-images"></span></p>';
code_args.code = '<div class="content" id="chat-content-' + id + '">' + code_args.mam + '</div>';
code_args.link = '<a href="#" class="tools-jingle-audio tools-tooltip talk-images chat-tools-content" title="' + Common._e("Call (audio only)") + '"></a>' +
'<a href="#" class="tools-jingle-video tools-tooltip talk-images chat-tools-content" title="' + Common._e("Call (video)") + '"></a>' +
'<a href="#" class="tools-infos tools-tooltip talk-images chat-tools-content" title="' + Common._e("Show user profile") + '"></a>';
code_args.style = ' style="display: none;"';
code_args.disabled = '';
}
// Not a groupchat private chat, we can use the buddy add icon
if((type == 'chat') || (type == 'groupchat')) {
var title;
if(type == 'chat') {
title = Common._e("Add this contact to your friends");
} else {
title = Common._e("Add this groupchat to your favorites");
}
code_args.link += '<a href="#" class="tools-add tools-tooltip talk-images chat-tools-content" title="' + title + '"></a>';
}
// IE DOM parsing bug fix
code_args.style_picker = '<div class="chat-tools-content chat-tools-style"' + code_args.style + '>' +
'<a href="#" class="tools-style tools-tooltip talk-images"></a>' +
'</div>';
if((BrowserDetect.browser == 'Explorer') && (BrowserDetect.version < 9)) {
code_args.style_picker = '';
}
} catch(e) {
Console.error('Chat._generateChatCode', e);
} finally {
return code_args;
}
};
/**
* Correctly opens a new chat
* @public
@ -34,38 +317,40 @@ var Chat = (function () {
try {
// No XID?
if(!xid)
if(!xid) {
return false;
}
// We generate some stuffs
var hash = hex_md5(xid);
var name;
// Gets the name of the user/title of the room
if(title)
if(title) {
name = title;
else {
} else {
// Private groupchat chat
if(type == 'private')
if(type == 'private') {
name = Common.thisResource(xid);
}
// XMPP-ID
else if(xid.indexOf('@') != -1)
else if(xid.indexOf('@') != -1) {
name = Name.getBuddy(xid);
}
// Gateway
else
else {
name = xid;
}
}
// If the target div does not exist
if(!Common.exists('#' + hash)) {
// We check the type of the chat to open
if((type == 'chat') || (type == 'private'))
if((type == 'chat') || (type == 'private')) {
self.create(hash, xid, name, type);
else if(type == 'groupchat') {
} else if(type == 'groupchat') {
// Try to read the room stored configuration
if(!Utils.isAnonymous() && (!nickname || !password || !title)) {
// Catch the room data
@ -115,71 +400,21 @@ var Chat = (function () {
var escaped_xid = escape(xid);
// Special code
var specialAttributes, specialAvatar, specialName, specialCode, specialLink, specialDisabled, specialStyle, specialMAM;
// Groupchat special code
if(type == 'groupchat') {
specialAttributes = ' data-type="groupchat"';
specialAvatar = '';
specialName = '<p class="bc-infos"><b>' + Common._e("Subject") + '</b> <span class="muc-topic">' + Common._e("no subject defined for this room.") + '</span></p>';
specialCode = '<div class="content groupchat-content" id="chat-content-' + id + '"></div><div class="list"><div class="moderator role"><p class="title">' + Common._e("Moderators") + '</p></div><div class="participant role"><p class="title">' + Common._e("Participants") + '</p></div><div class="visitor role"><p class="title">' + Common._e("Visitors") + '</p></div><div class="none role"><p class="title">' + Common._e("Others") + '</p></div></div>';
specialLink = '<a href="#" class="tools-mucadmin tools-tooltip talk-images chat-tools-content" title="' + Common._e("Administration panel for this room") + '"></a>';
specialStyle = '';
// Is this a gateway?
if(xid.match(/%/))
specialDisabled = '';
else
specialDisabled = ' disabled=""';
}
// Chat (or other things?!) special code
else {
specialMAM = '<div class="wait-mam wait-small"></div>';
specialAttributes = ' data-type="chat"';
specialAvatar = '<div class="avatar-container"><img class="avatar" src="' + './images/others/default-avatar.png' + '" alt="" /></div>';
specialName = '<div class="bc-pep"></div><p class="bc-infos"><span class="unavailable show talk-images"></span></p>';
specialCode = '<div class="content" id="chat-content-' + id + '">' + specialMAM + '</div>';
specialLink = '<a href="#" class="tools-jingle-audio tools-tooltip talk-images chat-tools-content" title="' + Common._e("Call (audio only)") + '"></a>' +
'<a href="#" class="tools-jingle-video tools-tooltip talk-images chat-tools-content" title="' + Common._e("Call (video)") + '"></a>' +
'<a href="#" class="tools-infos tools-tooltip talk-images chat-tools-content" title="' + Common._e("Show user profile") + '"></a>';
specialStyle = ' style="display: none;"';
specialDisabled = '';
}
// Not a groupchat private chat, we can use the buddy add icon
if((type == 'chat') || (type == 'groupchat')) {
var addTitle;
if(type == 'chat')
addTitle = Common._e("Add this contact to your friends");
else
addTitle = Common._e("Add this groupchat to your favorites");
specialLink += '<a href="#" class="tools-add tools-tooltip talk-images chat-tools-content" title="' + addTitle + '"></a>';
}
// IE DOM parsing bug fix
var specialStylePicker = '<div class="chat-tools-content chat-tools-style"' + specialStyle + '>' +
'<a href="#" class="tools-style tools-tooltip talk-images"></a>' +
'</div>';
if((BrowserDetect.browser == 'Explorer') && (BrowserDetect.version < 9))
specialStylePicker = '';
var chat_args = self._generateChatCode(type, id);
// Append the chat HTML code
$('#page-engine').append(
'<div id="' + id + '" class="page-engine-chan chat one-counter"' + specialAttributes + ' data-xid="' + escaped_xid + '">' +
'<div id="' + id + '" class="page-engine-chan chat one-counter"' + chat_args.attributes + ' data-xid="' + escaped_xid + '">' +
'<div class="top ' + id + '">' +
specialAvatar +
chat_args.avatar +
'<div class="name">' +
'<p class="bc-name bc-name-nick">' + nick.htmlEnc() + '</p>' +
specialName +
chat_args.name +
'</div>' +
'</div>' +
specialCode +
chat_args.code +
'<div class="text">' +
'<div class="footer">' +
@ -187,7 +422,7 @@ var Chat = (function () {
'<a href="#" class="tools-smileys tools-tooltip talk-images"></a>' +
'</div>' +
specialStylePicker +
chat_args.style_picker +
'<div class="chat-tools-content chat-tools-file">' +
'<a href="#" class="tools-file tools-tooltip talk-images"></a>' +
@ -199,35 +434,17 @@ var Chat = (function () {
'<a href="#" class="tools-clear tools-tooltip talk-images chat-tools-content" title="' + Common._e("Clean current chat") + '"></a>' +
specialLink +
chat_args.link +
'</div>' +
'<div class="compose">' +
'<textarea class="message-area focusable" ' + specialDisabled + ' data-to="' + escaped_xid + '" /></textarea>' +
'<textarea class="message-area focusable" ' + chat_args.disabled + ' data-to="' + escaped_xid + '" /></textarea>' +
'</div>' +
'</div>' +
'</div>'
);
// Click event: chat cleaner
$(path + 'tools-clear').click(function() {
self.clean(id);
});
// Click event: call (audio)
$(path + 'tools-jingle-audio').click(function() {
Jingle.start(xid, 'audio');
});
// Click event: call (video)
$(path + 'tools-jingle-video').click(function() {
Jingle.start(xid, 'video');
});
// Click event: user-infos
$(path + 'tools-infos').click(function() {
UserInfos.open(xid);
});
self._generateEvents(path, id, xid);
} catch(e) {
Console.error('Chat.generate', e);
}
@ -251,26 +468,32 @@ var Chat = (function () {
var chat_switch = '#page-switch .';
// Special code
var specialClass = ' unavailable';
var special_class = ' unavailable';
var show_close = true;
// Groupchat
if(type == 'groupchat') {
specialClass = ' groupchat-default';
special_class = ' groupchat-default';
if(Utils.isAnonymous() && (xid == Common.generateXID(ANONYMOUS_ROOM, 'groupchat')))
if(Utils.isAnonymous() && (xid == Common.generateXID(ANONYMOUS_ROOM, 'groupchat'))) {
show_close = false;
}
}
// Generate the HTML code
var html = '<div class="' + id + ' switcher chan" onclick="return Interface.switchChan(\'' + Utils.encodeOnclick(id) + '\')">' +
'<div class="icon talk-images' + specialClass + '"></div>' +
'<div class="name">' + nick.htmlEnc() + '</div>';
'<div class="icon talk-images' + special_class + '"></div>' +
'<div class="name">' + nick.htmlEnc() + '</div>';
// Show the close button if not MUC and not anonymous
if(show_close)
html += '<div class="exit" title="' + Common._e("Close this tab") + '" onclick="return Interface.quitThisChat(\'' + Utils.encodeOnclick(xid) + '\', \'' + Utils.encodeOnclick(id) + '\', \'' + Utils.encodeOnclick(type) + '\');">x</div>';
if(show_close) {
html += '<div class="exit" ' +
'title="' + Common._e("Close this tab") + '" ' +
'onclick="return Interface.quitThisChat(\'' + Utils.encodeOnclick(xid) + '\', \'' + Utils.encodeOnclick(id) + '\', \'' + Utils.encodeOnclick(type) + '\');">' +
'x' +
'</div>';
}
// Close the HTML
html += '</div>';
@ -353,7 +576,7 @@ var Chat = (function () {
// 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()) {
@ -373,32 +596,43 @@ var Chat = (function () {
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();
@ -406,6 +640,7 @@ var Chat = (function () {
// Send the subscribe request
Roster.addThisContact(xid, nick);
}).show();
}
}
// We catch the user's informations (like this avatar, vcard, and so on...)
@ -415,81 +650,12 @@ var Chat = (function () {
Tooltip.icons(xid, hash);
// The event handlers
var inputDetect = $('#page-engine #' + hash + ' .message-area');
var input_sel = $('#page-engine #' + hash + ' .message-area');
self._createEvents(input_sel, xid, hash);
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;
}
});
// 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);
}

View file

@ -36,8 +36,9 @@ var ChatState = (function () {
// 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);
@ -48,7 +49,9 @@ var ChatState = (function () {
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);
@ -76,8 +79,9 @@ var ChatState = (function () {
self.reset(hash, type);
// "gone" state not allowed
if(state != 'gone')
if(state != 'gone') {
$('#page-engine .page-engine-chan .user.' + hash).addClass(state);
}
}
// Chat
@ -125,7 +129,9 @@ var ChatState = (function () {
$('#' + hash + ' .chatstate').remove();
// We create the chatstate
$('#' + hash + ' .content').after('<div class="' + state + ' chatstate">' + text + '</div>');
$('#' + hash + ' .content').after(
'<div class="' + state + ' chatstate">' + text + '</div>'
);
}
} catch(e) {
Console.error('ChatState.display', e);
@ -147,10 +153,11 @@ var ChatState = (function () {
// 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');
@ -202,30 +209,33 @@ var ChatState = (function () {
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);

View file

@ -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,20 +147,21 @@ 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;
// Gateway XID
if(self.isDomain(xid) === true) {
return xid;
}
// It might be a gateway?
return xid;
// User XID
return xid + '@' + HOST_MAIN;
}
// Nothing special (yet bare XID)
@ -190,14 +218,16 @@ 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) {
@ -223,10 +253,11 @@ var Common = (function () {
// 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
@ -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
@ -360,8 +426,8 @@ var Common = (function () {
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;
@ -386,8 +452,9 @@ var Common = (function () {
var resource = self.thisResource(xid);
// Any resource?
if(resource)
if(resource) {
full += '/' + resource;
}
return full;
} catch(e) {
@ -401,14 +468,18 @@ 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) {
@ -549,7 +620,7 @@ var Common = (function () {
is_gateway = true;
try {
if(xid.indexOf('@') != -1) {
if(xid.indexOf('@') !== -1) {
is_gateway = false;
}
} catch(e) {
@ -618,12 +689,14 @@ 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;
@ -643,23 +716,31 @@ var Common = (function () {
*/
self.escapeRegex = function(query) {
if (query instanceof Array) {
var result = new Array(query.length);
for(i=0; i<query.length; i++) {
var result = [];
try {
if(query instanceof Array) {
result = [query.length];
for(i = 0; i < query.length; i++) {
try {
result[i] = Common.escapeRegex(query[i]);
} catch(e) {
Console.error('Common.escapeRegex', e);
result[i] = null;
}
}
} else {
try {
result[i] = Common.escapeRegex(query[i]);
result = query.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
} catch(e) {
Console.error('Common.escapeRegex', e);
result[i] = null;
Console.error('Common.escapeRegex[inner]', e);
}
}
} catch(e) {
Console.error('Common.escapeRegex', e);
} finally {
return result;
} else {
try {
return query.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
} catch(e) {
Console.error('Common.escapeRegex', e);
}
}
};

View file

@ -29,6 +29,205 @@ var Connection = (function () {
self.resume = false;
/**
* Do registration on Register API
* @private
* @param {string} username
* @param {string} domain
* @param {string} pass
* @param {string} captcha
* @return {boolean}
*/
self._doRegisterAPI = function(username, domain, pass, captcha) {
var is_success = false;
try {
// 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') {
is_success = true;
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, '');
}
}
});
} catch(e) {
Console.error('Connection._doRegisterAPI', e);
} finally {
return is_success;
}
};
/**
* Do registration throug in-band stream
* @private
* @param {string} username
* @param {string} domain
* @param {string} pass
* @return {boolean}
*/
self._doRegisterInBand = function(username, domain, pass) {
var is_success = true;
try {
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);
con.connect({
'domain': $.trim(domain),
'username': $.trim(username),
'resource': JAPPIX_RESOURCE + ' Register (' + (new Date()).getTime() + ')',
'pass': pass,
'register': true,
'secure': true,
'xmllang': XML_LANG
});
// Show the waiting image
Interface.showGeneralWait();
// Change the page title
Interface.title('wait');
} catch(e) {
Console.error('Connection._doRegisterInBand', e);
is_success = false;
} finally {
return is_success;
}
};
/**
* Attaches reconnect events
* @private
* @param {string} mode
* @return {undefined}
*/
self._eventsReconnect = function(mode) {
try {
// Click events
if(mode == 'normal') {
$('#reconnect a.finish.cancel').click(function() {
return self.cancelReconnect();
});
}
$('#reconnect a.finish.reconnect').click(function() {
return self.acceptReconnect(mode);
});
} catch(e) {
Console.error('Connection._eventsReconnect', e);
}
};
/**
* Schedules the next auto reconnect
* @private
* @param {string} mode
* @return {undefined}
*/
self._scheduleReconnect = function(mode) {
try {
// Try to reconnect automatically after a while
if(self.reconnect_try < 5) {
self.reconnect_timer = 5 + (5 * self.reconnect_try);
} else {
self.reconnect_timer = 120;
}
// Change the try number
self.reconnect_try++;
// Fire the event!
$('#reconnect a.finish.reconnect').everyTime('1s', function() {
// We can reconnect!
if(self.reconnect_timer === 0) {
return self.acceptReconnect(mode);
}
// Button text
if(self.reconnect_timer <= 10) {
$(this).text(Common._e("Reconnect") + ' (' + self.reconnect_timer + ')');
}
// Remove 1 second
self.reconnect_timer--;
});
} catch(e) {
Console.error('Connection._scheduleReconnect', e);
}
};
/**
* Does the user login
* @public
@ -45,7 +244,7 @@ var Connection = (function () {
try {
// get optionnal conn handlers
oExtend = loginOpts || {};
extend_obj = loginOpts || {};
// We remove the not completed class to avoid problems
$('#home .loginer input').removeClass('please-complete');
@ -71,7 +270,7 @@ var Connection = (function () {
}
// And we handle everything that happen
self.setupCon(con, oExtend);
self.setupCon(con, extend_obj);
// Generate a resource
var random_resource = DataStore.getDB(self.desktop_hash, 'session', 'resource');
@ -79,17 +278,17 @@ var Connection = (function () {
if(!random_resource) {
random_resource = lResource + ' (' + (new Date()).getTime() + ')';
}
// We retrieve what the user typed in the login inputs
oArgs = {};
oArgs.domain = $.trim(lServer);
oArgs.username = $.trim(lNick);
oArgs.resource = random_resource;
oArgs.pass = lPass;
oArgs.secure = true;
oArgs.xmllang = XML_LANG;
self.desktop_hash = 'jd.' + hex_md5(oArgs.username + '@' + oArgs.domain);
var con_args = {
'domain': lServer.trim(),
'username': lNick.trim(),
'resource': random_resource,
'pass': lPass,
'secure': true,
'xmllang': XML_LANG
};
self.desktop_hash = 'jd.' + hex_md5(con_args.username + '@' + con_args.domain);
// Store the resource (for reconnection)
DataStore.setDB(self.desktop_hash, 'session', 'resource', random_resource);
@ -101,7 +300,7 @@ var Connection = (function () {
DataStore.setDB(self.desktop_hash, 'priority', 1, lPriority);
// We connect !
con.connect(oArgs);
con.connect(con_args);
// Change the page title
Interface.title('wait');
@ -169,7 +368,9 @@ var Connection = (function () {
// We change the registered information text
$('#home .homediv.registerer').append(
'<div class="info success">' +
Common._e("You have been registered, here is your XMPP address:") + ' <b>' + username.htmlEnc() + '@' + domain.htmlEnc() + '</b> - <a href="#">' + Common._e("Login") + '</a>' +
Common._e("You have been registered, here is your XMPP address:") +
' <b>' + username.htmlEnc() + '@' + domain.htmlEnc() + '</b> - ' +
'<a href="#">' + Common._e("Login") + '</a>' +
'</div>'
);
@ -179,102 +380,9 @@ var Connection = (function () {
});
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);
@ -295,30 +403,28 @@ var Connection = (function () {
try {
Console.info('Trying to login anonymously...');
var aPath = '#home .anonymouser ';
var room = $(aPath + '.room').val();
var nick = $(aPath + '.nick').val();
var path_sel = $('#home .anonymouser');
var room = path_sel.find('.room').val();
var nick = path_sel.find('.nick').val();
// If the form is correctly completed
// 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);
} else {
path_sel.find('input[type="text"]').each(function() {
var this_sel = $(this);
if(!select.val())
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) {
@ -355,7 +461,7 @@ var Connection = (function () {
Interface.removeGeneralWait();
// Init Jingle
Jingle.init();
Call.init();
} catch(e) {
Console.error('Connection.handleConnected', e);
}
@ -374,8 +480,9 @@ 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();
@ -431,24 +538,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 || {};
extend_obj = extend_obj || {};
jQuery.each(oExtend, function(keywd,funct) {
jQuery.each(extend_obj, function(keywd,funct) {
con.registerHandler(keywd, funct);
});
} catch(e) {
@ -559,51 +674,25 @@ var Connection = (function () {
// Create the HTML code
var html = '<div id="reconnect" class="lock">' +
'<div class="pane">' +
Common._e("Due to a network issue, you were disconnected. What do you want to do now?");
'<div class="pane">' +
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 += '<a href="#" class="finish cancel">' + Common._e("Cancel") + '</a>';
}
html += '<a href="#" class="finish reconnect">' + Common._e("Reconnect") + '</a>' +
'</div></div>';
'</div></div>';
// Append the code
$('body').append(html);
// Click events
if(mode == 'normal')
$('#reconnect a.finish.cancel').click(function() {
return self.cancelReconnect();
});
// Attach events
self._eventsReconnect(mode);
$('#reconnect a.finish.reconnect').click(function() {
return self.acceptReconnect(mode);
});
// Try to reconnect automatically after a while
if(self.reconnect_try < 5)
self.reconnect_timer = 5 + (5 * self.reconnect_try);
else
self.reconnect_timer = 120;
// Change the try number
self.reconnect_try++;
// Fire the event!
$('#reconnect a.finish.reconnect').everyTime('1s', function() {
// We can reconnect!
if(self.reconnect_timer === 0)
return self.acceptReconnect(mode);
// Button text
if(self.reconnect_timer <= 10)
$(this).text(Common._e("Reconnect") + ' (' + self.reconnect_timer + ')');
// Remove 1 second
self.reconnect_timer--;
});
// Schedule next reconnect
self._scheduleReconnect(mode);
// Page title
Interface.updateTitle();
@ -634,9 +723,11 @@ var Connection = (function () {
// Reset some various stuffs
var groupchats = '#page-engine .page-engine-chan[data-type="groupchat"]';
$(groupchats + ' .list .role').hide();
$(groupchats + ' .one-group, ' + groupchats + ' .list .user').remove();
$(groupchats).attr('data-initial', 'false');
var groupchats_sel = $(groupchats);
groupchats_sel.find('.list .role').hide();
groupchats_sel.find('.one-group, ' + groupchats + ' .list .user').remove();
groupchats_sel.attr('data-initial', 'false');
// Stop the timer
$('#reconnect a.finish.reconnect').stopTime();
@ -645,10 +736,11 @@ var Connection = (function () {
$('#reconnect').remove();
// Try to login again
if(mode == 'normal')
if(mode == 'normal') {
self.loginFromSession(Common.XMLFromString(self.current_session));
else if(mode == 'anonymous')
} else if(mode == 'anonymous') {
Anonymous.login(HOST_ANONYMOUS);
}
} catch(e) {
Console.error('Connection.acceptReconnect', e);
} finally {
@ -817,7 +909,14 @@ var Connection = (function () {
try {
// Generate a session XML to be stored
session_xml = '<session><stored>true</stored><domain>' + lServer.htmlEnc() + '</domain><username>' + lNick.htmlEnc() + '</username><resource>' + lResource.htmlEnc() + '</resource><password>' + lPass.htmlEnc() + '</password><priority>' + lPriority.htmlEnc() + '</priority></session>';
session_xml = '<session>' +
'<stored>true</stored>' +
'<domain>' + lServer.htmlEnc() + '</domain>' +
'<username>' + lNick.htmlEnc() + '</username>' +
'<resource>' + lResource.htmlEnc() + '</resource>' +
'<password>' + lPass.htmlEnc() + '</password>' +
'<priority>' + lPriority.htmlEnc() + '</priority>' +
'</session>';
// Save the session parameters (for reconnect if network issue)
self.current_session = session_xml;
@ -848,8 +947,9 @@ var Connection = (function () {
$(window).bind('beforeunload', Connection.terminate);
// Nothing to do when anonymous!
if(Utils.isAnonymous())
if(Utils.isAnonymous()) {
return;
}
// Connection params submitted in URL?
if(XMPPLinks.links_var.u && XMPPLinks.links_var.q) {
@ -865,7 +965,15 @@ var Connection = (function () {
// Must store session?
if(XMPPLinks.links_var.h && (XMPPLinks.links_var.h === '1')) {
// Store session
var session_xml = self.storeSession(login_nick, login_server, login_pwd, login_resource, login_priority, true);
var session_xml = self.storeSession(
login_nick,
login_server,
login_pwd,
login_resource,
login_priority,
true
);
DataStore.setPersistent('global', 'session', 1, session_xml);
// Redirect to a clean URL
@ -900,10 +1008,7 @@ var Connection = (function () {
self.loginFromSession(session);
Console.info('Saved session found, resuming it...');
}
// Not connected, maybe a XMPP link is submitted?
else if((parent.location.hash != '#OK') && XMPPLinks.links_var.x) {
} else if((parent.location.hash != '#OK') && XMPPLinks.links_var.x) {
Home.change('loginer');
Console.info('A XMPP link is set, switch to login page.');

View file

@ -11,103 +11,109 @@ Authors: Stefan Strigler, Valérian Saliou, Kloadut, Maranda
*/
// XMPP XMLNS attributes
var NS_PROTOCOL = 'http://jabber.org/protocol/';
var NS_FEATURES = 'http://jabber.org/features/';
var NS_CLIENT = 'jabber:client';
var NS_IQ = 'jabber:iq:';
var NS_X = 'jabber:x:';
var NS_IETF = 'urn:ietf:params:xml:ns:';
var NS_IETF_XMPP = NS_IETF + 'xmpp-';
var NS_XMPP = 'urn:xmpp:';
var NS_PROTOCOL = 'http://jabber.org/protocol/';
var NS_FEATURES = 'http://jabber.org/features/';
var NS_CLIENT = 'jabber:client';
var NS_IQ = 'jabber:iq:';
var NS_X = 'jabber:x:';
var NS_IETF = 'urn:ietf:params:xml:ns:';
var NS_IETF_XMPP = NS_IETF + 'xmpp-';
var NS_XMPP = 'urn:xmpp:';
var NS_STORAGE = 'storage:';
var NS_BOOKMARKS = NS_STORAGE + 'bookmarks';
var NS_ROSTERNOTES = NS_STORAGE + 'rosternotes';
var NS_STORAGE = 'storage:';
var NS_BOOKMARKS = NS_STORAGE + 'bookmarks';
var NS_ROSTERNOTES = NS_STORAGE + 'rosternotes';
var NS_JAPPIX = 'jappix:';
var NS_INBOX = NS_JAPPIX + 'inbox';
var NS_OPTIONS = NS_JAPPIX + 'options';
var NS_JAPPIX = 'jappix:';
var NS_INBOX = NS_JAPPIX + 'inbox';
var NS_OPTIONS = NS_JAPPIX + 'options';
var NS_DISCO_ITEMS = NS_PROTOCOL + 'disco#items';
var NS_DISCO_INFO = NS_PROTOCOL + 'disco#info';
var NS_VCARD = 'vcard-temp';
var NS_VCARD_P = NS_VCARD + ':x:update';
var NS_IETF_VCARD4 = NS_IETF + 'vcard-4.0';
var NS_XMPP_VCARD4 = NS_XMPP + 'vcard4';
var NS_URN_ADATA = NS_XMPP + 'avatar:data';
var NS_URN_AMETA = NS_XMPP + 'avatar:metadata';
var NS_AUTH = NS_IQ + 'auth';
var NS_AUTH_ERROR = NS_IQ + 'auth:error';
var NS_REGISTER = NS_IQ + 'register';
var NS_SEARCH = NS_IQ + 'search';
var NS_ROSTER = NS_IQ + 'roster';
var NS_PRIVACY = NS_IQ + 'privacy';
var NS_PRIVATE = NS_IQ + 'private';
var NS_VERSION = NS_IQ + 'version';
var NS_TIME = NS_IQ + 'time';
var NS_LAST = NS_IQ + 'last';
var NS_IQDATA = NS_IQ + 'data';
var NS_XDATA = NS_X + 'data';
var NS_IQOOB = NS_IQ + 'oob';
var NS_XOOB = NS_X + 'oob';
var NS_DELAY = NS_X + 'delay';
var NS_EXPIRE = NS_X + 'expire';
var NS_EVENT = NS_X + 'event';
var NS_XCONFERENCE = NS_X + 'conference';
var NS_STATS = NS_PROTOCOL + 'stats';
var NS_MUC = NS_PROTOCOL + 'muc';
var NS_MUC_USER = NS_MUC + '#user';
var NS_MUC_ADMIN = NS_MUC + '#admin';
var NS_MUC_OWNER = NS_MUC + '#owner';
var NS_MUC_CONFIG = NS_MUC + '#roomconfig';
var NS_PUBSUB = NS_PROTOCOL + 'pubsub';
var NS_PUBSUB_EVENT = NS_PUBSUB + '#event';
var NS_PUBSUB_OWNER = NS_PUBSUB + '#owner';
var NS_PUBSUB_NMI = NS_PUBSUB + '#node-meta-info';
var NS_PUBSUB_NC = NS_PUBSUB + '#node_config';
var NS_PUBSUB_CN = NS_PUBSUB + '#config-node';
var NS_PUBSUB_RI = NS_PUBSUB + '#retrieve-items';
var NS_COMMANDS = NS_PROTOCOL + 'commands';
var NS_BOSH = NS_PROTOCOL + 'httpbind';
var NS_DISCO_ITEMS = NS_PROTOCOL + 'disco#items';
var NS_DISCO_INFO = NS_PROTOCOL + 'disco#info';
var NS_VCARD = 'vcard-temp';
var NS_VCARD_P = NS_VCARD + ':x:update';
var NS_IETF_VCARD4 = NS_IETF + 'vcard-4.0';
var NS_XMPP_VCARD4 = NS_XMPP + 'vcard4';
var NS_URN_ADATA = NS_XMPP + 'avatar:data';
var NS_URN_AMETA = NS_XMPP + 'avatar:metadata';
var NS_AUTH = NS_IQ + 'auth';
var NS_AUTH_ERROR = NS_IQ + 'auth:error';
var NS_REGISTER = NS_IQ + 'register';
var NS_SEARCH = NS_IQ + 'search';
var NS_ROSTER = NS_IQ + 'roster';
var NS_PRIVACY = NS_IQ + 'privacy';
var NS_PRIVATE = NS_IQ + 'private';
var NS_VERSION = NS_IQ + 'version';
var NS_TIME = NS_IQ + 'time';
var NS_LAST = NS_IQ + 'last';
var NS_IQDATA = NS_IQ + 'data';
var NS_XDATA = NS_X + 'data';
var NS_IQOOB = NS_IQ + 'oob';
var NS_XOOB = NS_X + 'oob';
var NS_DELAY = NS_X + 'delay';
var NS_EXPIRE = NS_X + 'expire';
var NS_EVENT = NS_X + 'event';
var NS_XCONFERENCE = NS_X + 'conference';
var NS_STATS = NS_PROTOCOL + 'stats';
var NS_MUC = NS_PROTOCOL + 'muc';
var NS_MUC_USER = NS_MUC + '#user';
var NS_MUC_ADMIN = NS_MUC + '#admin';
var NS_MUC_OWNER = NS_MUC + '#owner';
var NS_MUC_CONFIG = NS_MUC + '#roomconfig';
var NS_PUBSUB = NS_PROTOCOL + 'pubsub';
var NS_PUBSUB_EVENT = NS_PUBSUB + '#event';
var NS_PUBSUB_OWNER = NS_PUBSUB + '#owner';
var NS_PUBSUB_NMI = NS_PUBSUB + '#node-meta-info';
var NS_PUBSUB_NC = NS_PUBSUB + '#node_config';
var NS_PUBSUB_CN = NS_PUBSUB + '#config-node';
var NS_PUBSUB_RI = NS_PUBSUB + '#retrieve-items';
var NS_COMMANDS = NS_PROTOCOL + 'commands';
var NS_BOSH = NS_PROTOCOL + 'httpbind';
var NS_STREAM = 'http://etherx.jabber.org/streams';
var NS_URN_TIME = NS_XMPP + 'time';
var NS_URN_PING = NS_XMPP + 'ping';
var NS_URN_MBLOG = NS_XMPP + 'microblog:0';
var NS_URN_INBOX = NS_XMPP + 'inbox';
var NS_URN_FORWARD = NS_XMPP + 'forward:0';
var NS_URN_MAM = NS_XMPP + 'mam:tmp';
var NS_URN_DELAY = NS_XMPP + 'delay';
var NS_URN_RECEIPTS = NS_XMPP + 'receipts';
var NS_URN_CARBONS = NS_XMPP + 'carbons:2';
var NS_RSM = NS_PROTOCOL + 'rsm';
var NS_IPV6 = 'ipv6';
var NS_XHTML = 'http://www.w3.org/1999/xhtml';
var NS_XHTML_IM = NS_PROTOCOL + 'xhtml-im';
var NS_CHATSTATES = NS_PROTOCOL + 'chatstates';
var NS_HTTP_AUTH = NS_PROTOCOL + 'http-auth';
var NS_ROSTERX = NS_PROTOCOL + 'rosterx';
var NS_MOOD = NS_PROTOCOL + 'mood';
var NS_ACTIVITY = NS_PROTOCOL + 'activity';
var NS_TUNE = NS_PROTOCOL + 'tune';
var NS_GEOLOC = NS_PROTOCOL + 'geoloc';
var NS_NICK = NS_PROTOCOL + 'nick';
var NS_NOTIFY = '+notify';
var NS_CAPS = NS_PROTOCOL + 'caps';
var NS_ATOM = 'http://www.w3.org/2005/Atom';
var NS_URN_TIME = NS_XMPP + 'time';
var NS_URN_PING = NS_XMPP + 'ping';
var NS_URN_MBLOG = NS_XMPP + 'microblog:0';
var NS_URN_INBOX = NS_XMPP + 'inbox';
var NS_URN_FORWARD = NS_XMPP + 'forward:0';
var NS_URN_MAM = NS_XMPP + 'mam:tmp';
var NS_URN_DELAY = NS_XMPP + 'delay';
var NS_URN_RECEIPTS = NS_XMPP + 'receipts';
var NS_URN_CARBONS = NS_XMPP + 'carbons:2';
var NS_URN_CORRECT = NS_XMPP + 'message-correct:0';
var NS_URN_IDLE = NS_XMPP + 'idle:1';
var NS_URN_REACH = NS_XMPP + 'reach:0';
var NS_URN_MARKERS = NS_XMPP + 'chat-markers:0';
var NS_URN_ATTENTION = NS_XMPP + 'attention:0';
var NS_URN_HINTS = NS_XMPP + 'hints';
var NS_RSM = NS_PROTOCOL + 'rsm';
var NS_IPV6 = 'ipv6';
var NS_XHTML = 'http://www.w3.org/1999/xhtml';
var NS_XHTML_IM = NS_PROTOCOL + 'xhtml-im';
var NS_CHATSTATES = NS_PROTOCOL + 'chatstates';
var NS_HTTP_AUTH = NS_PROTOCOL + 'http-auth';
var NS_ROSTERX = NS_PROTOCOL + 'rosterx';
var NS_MOOD = NS_PROTOCOL + 'mood';
var NS_ACTIVITY = NS_PROTOCOL + 'activity';
var NS_TUNE = NS_PROTOCOL + 'tune';
var NS_GEOLOC = NS_PROTOCOL + 'geoloc';
var NS_NICK = NS_PROTOCOL + 'nick';
var NS_NOTIFY = '+notify';
var NS_CAPS = NS_PROTOCOL + 'caps';
var NS_ATOM = 'http://www.w3.org/2005/Atom';
var NS_STANZAS = NS_IETF_XMPP + 'stanzas';
var NS_STREAMS = NS_IETF_XMPP + 'streams';
var NS_STANZAS = NS_IETF_XMPP + 'stanzas';
var NS_STREAMS = NS_IETF_XMPP + 'streams';
var NS_TLS = NS_IETF_XMPP + 'tls';
var NS_SASL = NS_IETF_XMPP + 'sasl';
var NS_SESSION = NS_IETF_XMPP + 'session';
var NS_BIND = NS_IETF_XMPP + 'bind';
var NS_TLS = NS_IETF_XMPP + 'tls';
var NS_SASL = NS_IETF_XMPP + 'sasl';
var NS_SESSION = NS_IETF_XMPP + 'session';
var NS_BIND = NS_IETF_XMPP + 'bind';
var NS_FEATURE_IQAUTH = NS_FEATURES + 'iq-auth';
var NS_FEATURE_IQAUTH = NS_FEATURES + 'iq-auth';
var NS_FEATURE_IQREGISTER = NS_FEATURES + 'iq-register';
var NS_FEATURE_COMPRESS = NS_FEATURES + 'compress';
var NS_FEATURE_COMPRESS = NS_FEATURES + 'compress';
var NS_COMPRESS = NS_PROTOCOL + 'compress';
var NS_COMPRESS = NS_PROTOCOL + 'compress';
var NS_METRONOME_MAM_PURGE = 'http://metronome.im/protocol/mam-purge';

View file

@ -0,0 +1,509 @@
/*
Jappix - An open social platform
Implementation of XEP-0308: Last Message Correction
-------------------------------------------------
License: AGPL
Author: Valérian Saliou
*/
// Bundle
var Correction = (function () {
/**
* Alias of this
* @private
*/
var self = {};
/**
* @private
* @param {string} xid
* @return {boolean}
*/
self._hasSupport = function(xid) {
var support = false;
try {
if($('#' + hex_md5(xid) + '[data-correction="true"]').size()) {
support = true;
}
} catch(e) {
Console.error('Correction._hasSupport', e);
} finally {
return support;
}
};
/**
* @private
* @param {string} xid
* @return {string}
*/
self._getLastID = function(xid) {
var last_id = null;
try {
if(self._hasSupport(xid) === true) {
// Check last message from ourselves
last_id = $('#' + hex_md5(xid) + ' .content .one-line.user-message[data-mode="me"]:last').attr('data-id') || null;
}
} catch(e) {
Console.error('Correction._getLastID', e);
} finally {
return last_id;
}
};
/**
* @private
* @param {string} xid
* @return {string}
*/
self._getCurrentID = function(xid) {
var current_id = null;
try {
if(self._hasSupport(xid) === true) {
// Check the ID of the message being edited (if any)
current_id = $('#' + hex_md5(xid) + ' .message-area').attr('data-correction-current') || null;
}
} catch(e) {
Console.error('Correction._getCurrentID', e);
} finally {
return current_id;
}
};
/**
* @private
* @param {string} xid
* @return {object}
*/
self._getLastMessage = function(xid) {
var last_message_val = null;
var last_message_sel = null;
try {
if(self._hasSupport(xid) === true) {
// Check last message from ourselves
last_message_sel = $('#' + hex_md5(xid) + ' .content .one-line.user-message[data-mode="me"]:last');
last_message_val = last_message_sel.find('.message-content').text() || null;
if(last_message_val === null) {
last_message_sel = null;
}
}
} catch(e) {
Console.error('Correction._getLastMessage', e);
} finally {
return {
'value': last_message_val,
'selector': last_message_sel
};
}
};
/**
* @private
* @param {string} xid
* @param {object} message_sel
* @return {undefined}
*/
self._bindInterface = function(xid, message_sel) {
try {
// Add message area elements
var text_sel = $('#' + hex_md5(xid) + ' .text');
text_sel.addClass('correction-active');
text_sel.prepend(
'<div class="correction-toolbox">' +
'<span class="correction-editing">' + Common._e("Editing") + '</span>' +
'<a class="correction-cancel" href="#">' + Common._e("Cancel") + '</a>' +
'</div>'
);
// Add message correction marker
message_sel.addClass('correction-active');
message_sel.find('.correction-label').remove();
message_sel.find('.correction-edit').hide();
message_sel.append(
'<span class="correction-label">' +
Common._e("Being edited") +
'</span>'
);
// Bind click events
text_sel.find('.correction-cancel').click(function() {
self.leave(xid);
return false;
});
} catch(e) {
Console.error('Correction._bindInterface', e);
}
};
/**
* @private
* @param {string} xid
* @param {object} message_sel
* @return {undefined}
*/
self._unbindInterface = function(xid, message_sel) {
try {
// Remove message area elements
var text_sel = $('#' + hex_md5(xid) + ' .text');
text_sel.removeClass('correction-active');
text_sel.find('.correction-toolbox, .correction-label').remove();
if(message_sel.size()) {
message_sel.find('.correction-edit').css('display', '');
// Remove message correction marker
message_sel.removeClass('correction-active');
message_sel.find('.correction-label').remove();
}
} catch(e) {
Console.error('Correction._unbindInterface', e);
}
};
/**
* @private
* @param {string} xid
* @param {string} full_xid
* @param {string} type
* @param {string} message_id
* @param {string} message_body
* @return {string}
*/
self._sendStanza = function(xid, full_xid, type, message_id, message_body) {
var args = {
'id': null,
'xhtml': false,
'message': null
};
try {
var hash = hex_md5(xid);
var id = genID();
args.id = id;
// Initialize message stanza
var message = new JSJaCMessage();
args.message = message;
message.setType(type);
message.setTo(full_xid);
message.setID(id);
// Generates the correct message depending of the choosen style
var generate_message = Message.generate(message, message_body, hash);
args.xhtml = (generate_message === 'XHTML');
// Receipt request
var receipt_request = Receipts.request(hash);
if(receipt_request) {
message.appendNode('request', {'xmlns': NS_URN_RECEIPTS});
}
// Chatstate
message.appendNode('active', {'xmlns': NS_CHATSTATES});
if(message_id !== null) {
message.appendNode('replace', {
'xmlns': NS_URN_CORRECT,
'id': message_id
});
}
con.send(message, Errors.handleReply);
} catch(e) {
Console.error('Correction._sendStanza', e);
} finally {
return args;
}
};
/**
* Detects correction mode request (in input)
* @public
* @param {string} xid
* @param {object} input_sel
* @return {undefined}
*/
self.detect = function(xid, input_sel) {
try {
// Other keys
if(input_sel.val().match(/^\/correct/) && self.isIn(xid) === false) {
// Enter correction mode?
self.enter(xid);
}
} catch(e) {
Console.error('Correction.detect', e);
}
};
/**
* Enter correction mode (for last message)
* @public
* @param {string} xid
* @return {undefined}
*/
self.enter = function(xid) {
try {
Console.debug('Correction.enter', 'Requested to enter the correction mode with: ' + xid);
if(self._hasSupport(xid) === true && self.isIn(xid) === false) {
var last_message = self._getLastMessage(xid);
if(last_message.value && last_message.selector) {
Console.info('Correction.enter', 'Valid last message found for correction mode with: ' + xid);
var message_area_sel = $('#' + hex_md5(xid) + ' .message-area');
message_area_sel.val(last_message.value);
self._bindInterface(
xid,
last_message.selector
);
// Focus hack (to get cursor at the end of textarea)
message_area_sel.oneTime(10, function() {
message_area_sel[0].select();
message_area_sel[0].selectionStart = message_area_sel[0].selectionEnd;
});
}
}
} catch(e) {
Console.error('Correction.enter', e);
}
};
/**
* Leave correction mode
* @public
* @param {string} xid
* @return {undefined}
*/
self.leave = function(xid) {
try {
if(self.isIn(xid) === true) {
var base_sel = $('#' + hex_md5(xid));
var active_message_sel = base_sel.find('.content .one-line.user-message.correction-active');
self._unbindInterface(xid, active_message_sel);
var message_area_sel = base_sel.find('.message-area');
message_area_sel.val('');
message_area_sel.focus();
}
} catch(e) {
Console.error('Correction.leave', e);
}
};
/**
* Send corrected message
* @public
* @param {string} xid
* @param {string} type
* @param {string} replacement
* @return {undefined}
*/
self.send = function(xid, type, replacement) {
try {
if(self._hasSupport(xid) === true) {
if(self._getLastMessage(xid).value != replacement) {
var own_xid = Common.getXID();
var hash = hex_md5(xid);
var replace_id = self._getLastID(xid);
Console.info('Correction.send', 'Sending replacement message for: ' + xid + ' "' + replacement + '" with ID: ' + (replace_id || 'none'));
// Send the stanza itself
var full_xid = Presence.highestPriority(xid) || xid;
var stanza_args = self._sendStanza(
xid,
full_xid,
type,
replace_id,
replacement
);
// Update DOM (for chat only)
if(type == 'chat') {
// Filter the xHTML message (for us!)
var replacement_formatted = replacement;
if(stanza_args.xhtml) {
replacement_formatted = Filter.xhtml(stanza_args.message.getNode());
}
// Remove old message
old_message_sel = $('#' + hash + ' .content .one-line.user-message[data-mode="me"]').filter(function() {
return ($(this).attr('data-id') + '') === (replace_id + '');
}).filter(':last');
var edit_count = old_message_sel.attr('data-edit-count') || 0;
edit_count = isNaN(edit_count) ? 0 : parseInt(edit_count, 10);
if(type == 'chat') {
old_message_sel.remove();
}
// Display edited message
Message.display(
'chat',
own_xid,
hash,
Name.getBuddy(own_xid).htmlEnc(),
replacement_formatted,
DateUtils.getCompleteTime(),
DateUtils.getTimeStamp(),
'user-message',
!stanza_args.xhtml,
'',
'me',
stanza_args.id,
undefined,
undefined,
true,
(edit_count + 1)
);
}
}
}
} catch(e) {
Console.error('Correction.send', e);
}
};
/**
* Catches a replace message
* @public
* @param {object} message
* @param {string} hash
* @param {string} type
* @return {object}
*/
self.catch = function(message, hash, type) {
var edit_results = {
'has_replace': false,
'is_edited': false,
'count': 0,
'next_count': 0
};
try {
var replace_node = message.getChild('replace', NS_URN_CORRECT);
if(replace_node) {
edit_results.has_replace = true;
var message_edit_id = $(replace_node).attr('id');
if(typeof message_edit_id != 'undefined') {
var message_edit_sel = $('#' + hash + ' .one-line.user-message').filter(function() {
var this_sel = $(this);
var is_valid_mode = true;
if(type == 'chat') {
is_valid_mode = true ? this_sel.attr('data-mode') == 'him' : false;
}
return is_valid_mode && ((this_sel.attr('data-id') + '') === (message_edit_id + ''));
}).filter(':last');
if(message_edit_sel.size()) {
edit_results.count = message_edit_sel.attr('data-edit-count') || 0;
edit_results.count = isNaN(edit_results.count) ? 0 : parseInt(edit_results.count, 10);
edit_results.next_count = edit_results.count + 1;
edit_results.is_edited = true;
// Empty group?
var message_edit_group_sel = message_edit_sel.parents('.one-group');
if(message_edit_group_sel.find('.one-line').size() <= 1) {
message_edit_group_sel.remove();
} else {
message_edit_sel.remove();
}
}
}
}
} catch(e) {
Console.error('Correction.catch', e);
} finally {
return edit_results;
}
};
/**
* Returns whether we are in correction mode or not
* @public
* @param {string} xid
* @return {boolean}
*/
self.isIn = function(xid) {
var is_in = false;
try {
is_in = $('#' + hex_md5(xid) + ' .text').hasClass('correction-active');
} catch(e) {
Console.error('Correction.isIn', e);
} finally {
return is_in;
}
};
/**
* Return class scope
*/
return self;
})();

File diff suppressed because it is too large Load diff

View file

@ -39,8 +39,9 @@ var DataStore = (function () {
this.key = function(key) {
if(legacy) {
if(key >= this.length)
if(key >= this.length) {
return null;
}
var c = 0;
@ -56,8 +57,9 @@ var DataStore = (function () {
this.getItem = function(key) {
if(legacy) {
if(storage_emulated[key] !== undefined)
if(storage_emulated[key] !== undefined) {
return storage_emulated[key];
}
return null;
} else {
@ -67,8 +69,9 @@ var DataStore = (function () {
this.setItem = function(key, data) {
if(legacy) {
if(!(key in storage_emulated))
if(!(key in storage_emulated)) {
this.length++;
}
storage_emulated[key] = (data + '');
} else {
@ -472,8 +475,9 @@ var DataStore = (function () {
self.resetPersistent();
// Restaure the stored session entry
if(session)
if(session) {
self.setPersistent('global', 'session', 1, session);
}
Console.info('Persistent database flushed.');

View file

@ -84,8 +84,9 @@ var DateUtils = (function () {
try {
// Last activity not yet initialized?
if(self.last_activity === 0)
if(self.last_activity === 0) {
return 0;
}
return self.getTimeStamp() - self.last_activity;
} catch(e) {
@ -95,6 +96,27 @@ var DateUtils = (function () {
};
/**
* Gets the last user activity as a date
* @public
* @return {string}
*/
self.getLastActivityDate = function() {
try {
var last_activity = self.last_activity || self.getTimeStamp();
var last_date = new Date();
last_date.setTime(last_activity * 1000);
return self.getDatetime(last_date, 'utc');
} catch(e) {
Console.error('DateUtils.getLastActivityDate', e);
}
};
/**
* Gets the last user available presence in seconds
* @public
@ -104,8 +126,9 @@ var DateUtils = (function () {
try {
// Last presence stamp not yet initialized?
if(self.presence_last_activity === 0)
if(self.presence_last_activity === 0) {
return 0;
}
return self.getTimeStamp() - self.presence_last_activity;
} catch(e) {
@ -115,6 +138,56 @@ var DateUtils = (function () {
};
/**
* Generates a normalized datetime
* @public
* @param {Date} date
* @param {string} location
* @return {string}
*/
self.getDatetime = function(date, location) {
/* FROM : http://trac.jwchat.org/jsjac/browser/branches/jsjac_1.0/jsextras.js?rev=221 */
var year, month, day, hours, minutes, seconds;
var date_string = null;
try {
if(location == 'utc') {
// UTC date
year = date.getUTCFullYear();
month = date.getUTCMonth();
day = date.getUTCDate();
hours = date.getUTCHours();
minutes = date.getUTCMinutes();
seconds = date.getUTCSeconds();
} else {
// Local date
year = date.getFullYear();
month = date.getMonth();
day = date.getDate();
hours = date.getHours();
minutes = date.getMinutes();
seconds = date.getSeconds();
}
// Generates the date string
date_string = year + '-';
date_string += Common.padZero(month + 1) + '-';
date_string += Common.padZero(day) + 'T';
date_string += Common.padZero(hours) + ':';
date_string += Common.padZero(minutes) + ':';
date_string += Common.padZero(seconds) + 'Z';
// Returns the date string
return date_string;
} catch(e) {
Console.error('DateUtils.getDatetime', e);
}
};
/**
* Generates the time for XMPP
* @public
@ -123,43 +196,11 @@ var DateUtils = (function () {
*/
self.getXMPPTime = function(location) {
/* FROM : http://trac.jwchat.org/jsjac/browser/branches/jsjac_1.0/jsextras.js?rev=221 */
try {
// Initialize
var jInit = new Date();
var year, month, day, hours, minutes, seconds;
// Gets the UTC date
if(location == 'utc') {
year = jInit.getUTCFullYear();
month = jInit.getUTCMonth();
day = jInit.getUTCDate();
hours = jInit.getUTCHours();
minutes = jInit.getUTCMinutes();
seconds = jInit.getUTCSeconds();
}
// Gets the local date
else {
year = jInit.getFullYear();
month = jInit.getMonth();
day = jInit.getDate();
hours = jInit.getHours();
minutes = jInit.getMinutes();
seconds = jInit.getSeconds();
}
// Generates the date string
var jDate = year + '-';
jDate += Common.padZero(month + 1) + '-';
jDate += Common.padZero(day) + 'T';
jDate += Common.padZero(hours) + ':';
jDate += Common.padZero(minutes) + ':';
jDate += Common.padZero(seconds) + 'Z';
// Returns the date string
return jDate;
return self.getDatetime(
(new Date()),
location
);
} catch(e) {
Console.error('DateUtils.getXMPPTime', e);
}
@ -176,6 +217,7 @@ var DateUtils = (function () {
try {
var init = new Date();
var time = Common.padZero(init.getHours()) + ':';
time += Common.padZero(init.getMinutes()) + ':';
time += Common.padZero(init.getSeconds());
@ -332,20 +374,24 @@ var DateUtils = (function () {
var days = Math.round((current_stamp - old_stamp) / 86400000);
// Invalid date?
if(isNaN(old_stamp) || isNaN(days))
if(isNaN(old_stamp) || isNaN(days)) {
return self.getCompleteTime();
}
// Is it today?
if(current_day == old_day)
if(current_day == old_day) {
return old_time;
}
// It is yesterday?
if(days <= 1)
if(days <= 1) {
return Common._e("Yesterday") + ' - ' + old_time;
}
// Is it less than a week ago?
if(days <= 7)
if(days <= 7) {
return Common.printf(Common._e("%s days ago"), days) + ' - ' + old_time;
}
// Another longer period
return old_date.toLocaleDateString() + ' - ' + old_time;
@ -371,13 +417,12 @@ var DateUtils = (function () {
// Read the delay
d_delay = jQuery(node).find('delay[xmlns="' + NS_URN_DELAY + '"]:first').attr('stamp');
// New delay (valid XEP)
if(d_delay)
// Get delay
if(d_delay) {
// New delay (valid XEP)
delay = d_delay;
// Old delay (obsolete XEP!)
else {
// Try to read the old-school delay
} else {
// Old delay (obsolete XEP!)
var x_delay = jQuery(node).find('x[xmlns="' + NS_DELAY + '"]:first').attr('stamp');
if(x_delay)

View file

@ -1,10 +1,10 @@
/**
* Version: 1.0 Alpha-1
* Build Date: 13-Nov-2007
* Copyright (c) 2006-2007, Coolite Inc. (http://www.coolite.com/). All rights reserved.
* License: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/.
* Website: http://www.datejs.com/ or http://www.coolite.com/datejs/
*/
/**
* Version: 1.0 Alpha-1
* Build Date: 13-Nov-2007
* Copyright (c) 2006-2007, Coolite Inc. (http://www.coolite.com/). All rights reserved.
* License: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/.
* Website: http://www.datejs.com/ or http://www.coolite.com/datejs/
*/
Date.CultureInfo={name:"en-US",englishName:"English (United States)",nativeName:"English (United States)",dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],abbreviatedDayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],shortestDayNames:["Su","Mo","Tu","We","Th","Fr","Sa"],firstLetterDayNames:["S","M","T","W","T","F","S"],monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],abbreviatedMonthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],amDesignator:"AM",pmDesignator:"PM",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"mdy",formatPatterns:{shortDate:"M/d/yyyy",longDate:"dddd, MMMM dd, yyyy",shortTime:"h:mm tt",longTime:"h:mm:ss tt",fullDateTime:"dddd, MMMM dd, yyyy h:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^jan(uary)?/i,feb:/^feb(ruary)?/i,mar:/^mar(ch)?/i,apr:/^apr(il)?/i,may:/^may/i,jun:/^jun(e)?/i,jul:/^jul(y)?/i,aug:/^aug(ust)?/i,sep:/^sep(t(ember)?)?/i,oct:/^oct(ober)?/i,nov:/^nov(ember)?/i,dec:/^dec(ember)?/i,sun:/^su(n(day)?)?/i,mon:/^mo(n(day)?)?/i,tue:/^tu(e(s(day)?)?)?/i,wed:/^we(d(nesday)?)?/i,thu:/^th(u(r(s(day)?)?)?)?/i,fri:/^fr(i(day)?)?/i,sat:/^sa(t(urday)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\+|after|from)/i,subtract:/^(\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\.?m?\.?|p\.?m?\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt)/i,ordinalSuffix:/^\s*(st|nd|rd|th)/i,timeContext:/^\s*(\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
Date.getMonthNumberFromName=function(name){var n=Date.CultureInfo.monthNames,m=Date.CultureInfo.abbreviatedMonthNames,s=name.toLowerCase();for(var i=0;i<n.length;i++){if(n[i].toLowerCase()==s||m[i].toLowerCase()==s){return i;}}
return-1;};Date.getDayNumberFromName=function(name){var n=Date.CultureInfo.dayNames,m=Date.CultureInfo.abbreviatedDayNames,o=Date.CultureInfo.shortestDayNames,s=name.toLowerCase();for(var i=0;i<n.length;i++){if(n[i].toLowerCase()==s||m[i].toLowerCase()==s){return i;}}
@ -101,4 +101,4 @@ return _.any.apply(null,rx);}else{return _get(fx);}};g._formats=g.formats(["yyyy
return g._start.call({},s);};}());Date._parse=Date.parse;Date.parse=function(s){var r=null;if(!s){return null;}
try{r=Date.Grammar.start.call({},s);}catch(e){return null;}
return((r[1].length===0)?r[0]:null);};Date.getParseFunction=function(fx){var fn=Date.Grammar.formats(fx);return function(s){var r=null;try{r=fn.call({},s);}catch(e){return null;}
return((r[1].length===0)?r[0]:null);};};Date.parseExact=function(s,fx){return Date.getParseFunction(fx)(s);};
return((r[1].length===0)?r[0]:null);};};Date.parseExact=function(s,fx){return Date.getParseFunction(fx)(s);};

View file

@ -123,8 +123,9 @@ var Directory = (function () {
$('#directory .directory-server-input').keyup(function(e) {
if(e.keyCode == 13) {
// No value?
if(!$(this).val())
if(!$(this).val()) {
$(this).val(HOST_VJUD);
}
// Start the directory search
self.start();

View file

@ -216,8 +216,9 @@ var Discovery = (function () {
$('#discovery .disco-server-input').keyup(function(e) {
if(e.keyCode == 13) {
// No value?
if(!$(this).val())
if(!$(this).val()) {
$(this).val(HOST_MAIN);
}
// Start the discovery
self.start();

View file

@ -37,17 +37,20 @@ var Errors = (function () {
var eText = '';
// Any error condition
if(condition)
if(condition) {
eText += condition;
}
// Any error type
if(type && eText)
if(type && eText) {
eText += ' (' + type + ')';
}
// Any error reason
if(reason) {
if(eText)
if(eText) {
eText += ' - ';
}
eText += reason;
}
@ -119,10 +122,11 @@ var Errors = (function () {
// Show reconnect pane
if(Connection.current_session && Connection.connected) {
// Anonymous?
if(Utils.isAnonymous())
if(Utils.isAnonymous()) {
Connection.createReconnect('anonymous');
else
} else {
Connection.createReconnect('normal');
}
}
// Show the homepage (security)

View file

@ -143,16 +143,21 @@ var Favorites = (function () {
self.reset = function() {
try {
var path = '#favorites ';
var path_sel = $('#favorites');
$(path + '.wait, ' + path + '.fedit-terminate').hide();
$(path + '.fedit-add').show();
$(path + '.fsearch-oneresult').remove();
$(path + 'input').val('');
$(path + '.please-complete').removeClass('please-complete');
$(path + '.fedit-nick').val(Name.getNick());
$(path + '.fsearch-head-server, ' + path + '.fedit-server').val(HOST_MUC);
$(path + '.fedit-autojoin').removeAttr('checked');
path_sel.find('.wait');
path_sel.find('.fedit-terminate').hide();
path_sel.find('.fedit-add').show();
path_sel.find('.fsearch-oneresult').remove();
path_sel.find('input').val('');
path_sel.find('.please-complete').removeClass('please-complete');
path_sel.find('.fedit-nick').val(Name.getNick());
path_sel.find('.fsearch-head-server').val(HOST_MUC);
path_sel.find('.fedit-server').val(HOST_MUC);
path_sel.find('.fedit-autojoin').removeAttr('checked');
} catch(e) {
Console.error('Favorites.reset', e);
}
@ -182,29 +187,34 @@ var Favorites = (function () {
/**
* Adds a room to the favorites
* @public
* @param {string} roomXID
* @param {string} roomName
* @param {string} room_xid
* @param {string} room_name
* @return {boolean}
*/
self.addThis = function(roomXID, roomName) {
self.addThis = function(room_xid, room_name) {
try {
// Button path
var button = '#favorites .fsearch-results div[data-xid="' + escape(roomXID) + '"] a.one-button';
var button_sel = $('#favorites .fsearch-results div[data-xid="' + escape(room_xid) + '"] a.one-button');
// Add a remove button instead of the add one
$(button + '.add').replaceWith('<a href="#" class="one-button remove talk-images">' + Common._e("Remove") + '</a>');
button_sel.filter('.add').replaceWith(
'<a href="#" class="one-button remove talk-images">' + Common._e("Remove") + '</a>'
);
// Click event
$(button + '.remove').click(function() {
return self.removeThis(roomXID, roomName);
button_sel.filter('.remove').click(function() {
return self.removeThis(room_xid, room_name);
});
// Hide the add button in the (opened?) groupchat
$('#' + hex_md5(roomXID) + ' .tools-add').hide();
$('#' + hex_md5(room_xid) + ' .tools-add').hide();
// Add the database entry
self.display(roomXID, Common.explodeThis(' (', roomName, 0), Name.getNick(), '0', '');
self.display(
room_xid,
Common.explodeThis(' (', room_name, 0), Name.getNick(), '0', ''
);
// Publish the favorites
self.publish();
@ -220,29 +230,29 @@ var Favorites = (function () {
/**
* Removes a room from the favorites
* @public
* @param {string} roomXID
* @param {string} roomName
* @param {string} room_xid
* @param {string} room_name
* @return {boolean}
*/
self.removeThis = function(roomXID, roomName) {
self.removeThis = function(room_xid, room_name) {
try {
// Button path
var button = '#favorites .fsearch-results div[data-xid="' + escape(roomXID) + '"] a.one-button';
var button_sel = $('#favorites .fsearch-results div[data-xid="' + escape(room_xid) + '"] a.one-button');
// Add a remove button instead of the add one
$(button + '.remove').replaceWith('<a href="#" class="one-button add talk-images">' + Common._e("Add") + '</a>');
button_sel.filter('.remove').replaceWith('<a href="#" class="one-button add talk-images">' + Common._e("Add") + '</a>');
// Click event
$(button + '.add').click(function() {
return self.addThis(roomXID, roomName);
button_sel.filter('.add').click(function() {
return self.addThis(room_xid, room_name);
});
// Show the add button in the (opened?) groupchat
$('#' + hex_md5(roomXID) + ' .tools-add').show();
$('#' + hex_md5(room_xid) + ' .tools-add').show();
// Remove the favorite
self.remove(roomXID, true);
self.remove(room_xid, true);
// Publish the favorites
self.publish();
@ -264,31 +274,34 @@ var Favorites = (function () {
try {
// Path to favorites
var favorites = '#favorites .';
var favorites_sel = $('#favorites');
// Reset the favorites
self.reset();
// Show the edit/remove button, hide the others
$(favorites + 'fedit-terminate').hide();
$(favorites + 'fedit-edit').show();
$(favorites + 'fedit-remove').show();
favorites_sel.find('.fedit-terminate').hide();
favorites_sel.find('.fedit-edit').show();
favorites_sel.find('.fedit-remove').show();
// We retrieve the values
var xid = $(favorites + 'fedit-head-select').val();
var data = Common.XMLFromString(DataStore.getDB(Connection.desktop_hash, 'favorites', xid));
var xid = favorites_sel.find('.fedit-head-select').val();
var data_sel = $(Common.XMLFromString(
DataStore.getDB(Connection.desktop_hash, 'favorites', xid)
));
// If this is not the default room
if(xid != 'none') {
// We apply the values
$(favorites + 'fedit-title').val($(data).find('name').text());
$(favorites + 'fedit-nick').val($(data).find('nick').text());
$(favorites + 'fedit-chan').val(Common.getXIDNick(xid));
$(favorites + 'fedit-server').val(Common.getXIDHost(xid));
$(favorites + 'fedit-password').val($(data).find('password').text());
favorites_sel.find('.fedit-title').val(data_sel.find('name').text());
favorites_sel.find('.fedit-nick').val(data_sel.find('nick').text());
favorites_sel.find('.fedit-chan').val(Common.getXIDNick(xid));
favorites_sel.find('.fedit-server').val(Common.getXIDHost(xid));
favorites_sel.find('.fedit-password').val(data_sel.find('password').text());
if($(data).find('autojoin').text() == 'true')
$(favorites + 'fedit-autojoin').attr('checked', true);
if(data_sel.find('autojoin').text() == 'true') {
favorites_sel.find('.fedit-autojoin').attr('checked', true);
}
}
} catch(e) {
Console.error('Favorites.edit', e);
@ -307,52 +320,50 @@ var Favorites = (function () {
try {
// Path to favorites
var favorites = '#favorites ';
var favorites_sel = $('#favorites');
// We get the values of the current edited groupchat
var old_xid = $(favorites + '.fedit-head-select').val();
var old_xid = favorites_sel.find('.fedit-head-select').val();
var title = $(favorites + '.fedit-title').val();
var nick = $(favorites + '.fedit-nick').val();
var room = $(favorites + '.fedit-chan').val();
var server = $(favorites + '.fedit-server').val();
var title = favorites_sel.find('.fedit-title').val();
var nick = favorites_sel.find('.fedit-nick').val();
var room = favorites_sel.find('.fedit-chan').val();
var server = favorites_sel.find('.fedit-server').val();
var xid = room + '@' + server;
var password = $(favorites + '.fedit-password').val();
var password = favorites_sel.find('.fedit-password').val();
var autojoin = 'false';
if($(favorites + '.fedit-autojoin').filter(':checked').size())
if(favorites_sel.find('.fedit-autojoin').filter(':checked').size()) {
autojoin = 'true';
}
// We check the missing values and send this if okay
if((type == 'add') || (type == 'edit')) {
if(title && nick && room && server) {
// Remove the edited room
if(type == 'edit')
if(type == 'edit') {
self.remove(old_xid, true);
}
// Display the favorites
self.display(xid, title, nick, autojoin, password);
// Reset the inputs
self.reset();
}
else {
$(favorites + 'input[required]').each(function() {
} else {
favorites_sel.find('input[required]').each(function() {
var select = $(this);
if(!select.val())
if(!select.val()) {
$(document).oneTime(10, function() {
select.addClass('please-complete').focus();
});
else
} else {
select.removeClass('please-complete');
}
});
}
}
// Must remove a favorite?
else if(type == 'remove') {
} else if(type == 'remove') {
self.remove(old_xid, true);
// Reset the inputs
@ -409,7 +420,9 @@ var Favorites = (function () {
iq.setType('set');
var query = iq.setQuery(NS_PRIVATE);
var storage = query.appendChild(iq.buildNode('storage', {'xmlns': NS_BOOKMARKS}));
var storage = query.appendChild(iq.buildNode('storage', {
'xmlns': NS_BOOKMARKS
}));
// We generate the XML
var db_regex = new RegExp(('^' + Connection.desktop_hash + '_') + 'favorites_(.+)');
@ -420,19 +433,35 @@ var Favorites = (function () {
// If the pointer is on a stored favorite
if(current.match(db_regex)) {
var data = Common.XMLFromString(DataStore.storageDB.getItem(current));
var xid = $(data).find('xid').text();
var rName = $(data).find('name').text();
var nick = $(data).find('nick').text();
var password = $(data).find('password').text();
var autojoin = $(data).find('autojoin').text();
var data_sel = $(Common.XMLFromString(
DataStore.storageDB.getItem(current)
));
var xid = data_sel.find('xid').text();
var rName = data_sel.find('name').text();
var nick = data_sel.find('nick').text();
var password = data_sel.find('password').text();
var autojoin = data_sel.find('autojoin').text();
// We create the node for this groupchat
var item = storage.appendChild(iq.buildNode('conference', {'name': rName, 'jid': xid, 'autojoin': autojoin, xmlns: NS_BOOKMARKS}));
item.appendChild(iq.buildNode('nick', {xmlns: NS_BOOKMARKS}, nick));
var item = storage.appendChild(
iq.buildNode('conference', {
'name': rName,
'jid': xid,
'autojoin': autojoin,
xmlns: NS_BOOKMARKS
})
);
if(password)
item.appendChild(iq.buildNode('password', {xmlns: NS_BOOKMARKS}, password));
item.appendChild(iq.buildNode('nick', {
xmlns: NS_BOOKMARKS
}, nick));
if(password) {
item.appendChild(iq.buildNode('password', {
xmlns: NS_BOOKMARKS
}, password));
}
Console.info('Bookmark sent: ' + xid);
}
@ -454,17 +483,17 @@ var Favorites = (function () {
self.getGCList = function() {
try {
var path = '#favorites .';
var gcServer = $('.fsearch-head-server').val();
var path_sel = $('#favorites');
var groupchat_server = $('.fsearch-head-server').val();
// We reset some things
$(path + 'fsearch-oneresult').remove();
$(path + 'fsearch-noresults').hide();
$(path + 'wait').show();
path_sel.find('.fsearch-oneresult').remove();
path_sel.find('.fsearch-noresults').hide();
path_sel.find('.wait').show();
var iq = new JSJaCIQ();
iq.setType('get');
iq.setTo(gcServer);
iq.setTo(groupchat_server);
iq.setQuery(NS_DISCO_ITEMS);
@ -485,13 +514,13 @@ var Favorites = (function () {
self.handleGCList = function(iq) {
try {
var path = '#favorites .';
var path_sel = $('#favorites');
var from = Common.fullXID(Common.getStanzaFrom(iq));
if(!iq || (iq.getType() != 'result')) {
Board.openThisError(3);
$(path + 'wait').hide();
path_sel.find('.wait').hide();
Console.error('Error while retrieving the rooms: ' + from);
}
@ -504,24 +533,37 @@ var Favorites = (function () {
var html = '';
$(handleXML).find('item').each(function() {
var roomXID = $(this).attr('jid');
var roomName = $(this).attr('name');
var this_sel = $(this);
var room_xid = this_sel.attr('jid');
var room_name = this_sel.attr('name');
if(roomXID && roomName) {
if(room_xid && room_name) {
// Escaped values
var escaped_xid = Utils.encodeOnclick(roomXID);
var escaped_name = Utils.encodeOnclick(roomName);
var escaped_xid = Utils.encodeOnclick(room_xid);
var escaped_name = Utils.encodeOnclick(room_name);
// Initialize the room HTML
html += '<div class="oneresult fsearch-oneresult" data-xid="' + escape(roomXID) + '">' +
'<div class="room-name">' + roomName.htmlEnc() + '</div>' +
html += '<div class="oneresult fsearch-oneresult" data-xid="' + escape(room_xid) + '">' +
'<div class="room-name">' + room_name.htmlEnc() + '</div>' +
'<a href="#" class="one-button join talk-images" onclick="return Favorites.join(\'' + escaped_xid + '\');">' + Common._e("Join") + '</a>';
// This room is yet a favorite
if(DataStore.existDB('favorites', roomXID))
html += '<a href="#" class="one-button remove talk-images" onclick="return Favorites.removeThis(\'' + escaped_xid + '\', \'' + escaped_name + '\');">' + Common._e("Remove") + '</a>';
else
html += '<a href="#" class="one-button add talk-images" onclick="return Favorites.addThis(\'' + escaped_xid + '\', \'' + escaped_name + '\');">' + Common._e("Add") + '</a>';
if(DataStore.existDB(Connection.desktop_hash, 'favorites', room_xid)) {
html += '<a href="#" ' +
'class="one-button remove talk-images" ' +
'onclick="return Favorites.removeThis(\'' + escaped_xid + '\', \'' + escaped_name + '\');"' +
'>' +
Common._e("Remove") +
'</a>';
} else {
html += '<a href="#" ' +
'class="one-button add talk-images" ' +
'onclick="return Favorites.addThis(\'' + escaped_xid + '\', \'' + escaped_name + '\');"' +
'>' +
Common._e("Add") +
'</a>';
}
// Close the room HTML
html += '</div>';
@ -529,16 +571,15 @@ var Favorites = (function () {
});
// Append this code to the popup
$(path + 'fsearch-results').append(html);
path_sel.find('.fsearch-results').append(html);
} else {
path_sel.find('.fsearch-noresults').show();
}
else
$(path + 'fsearch-noresults').show();
Console.info('Rooms retrieved: ' + from);
}
$(path + 'wait').hide();
path_sel.find('.wait').hide();
} catch(e) {
Console.error('Favorites.handleGCList', e);
}
@ -556,7 +597,14 @@ var Favorites = (function () {
try {
self.quit();
Chat.checkCreate(room, 'groupchat', '', '', Common.getXIDNick(room));
Chat.checkCreate(
room,
'groupchat',
'',
'',
Common.getXIDNick(room)
);
} catch(e) {
Console.error('Favorites.join', e);
} finally {
@ -589,7 +637,14 @@ var Favorites = (function () {
$('#roster .gc-join-first-option, #favorites .fedit-head-select-first-option').after(html);
// We store the informations
var value = '<groupchat><xid>' + xid.htmlEnc() + '</xid><name>' + name.htmlEnc() + '</name><nick>' + nick.htmlEnc() + '</nick><autojoin>' + autojoin.htmlEnc() + '</autojoin><password>' + password.htmlEnc() + '</password></groupchat>';
var value = '<groupchat>' +
'<xid>' + xid.htmlEnc() + '</xid>' +
'<name>' + name.htmlEnc() + '</name>' +
'<nick>' + nick.htmlEnc() + '</nick>' +
'<autojoin>' + autojoin.htmlEnc() + '</autojoin>' +
'<password>' + password.htmlEnc() + '</password>' +
'</groupchat>';
DataStore.setDB(Connection.desktop_hash, 'favorites', xid, value);
} catch(e) {
Console.error('Favorites.display', e);
@ -621,13 +676,20 @@ var Favorites = (function () {
var data = Common.XMLFromString(DataStore.storageDB.getItem(current));
// Add the current favorite to the HTML code
html += '<option value="' + Common.encodeQuotes($(data).find('xid').text()) + '">' + $(data).find('name').text().htmlEnc() + '</option>';
html += '<option value="' + Common.encodeQuotes($(data).find('xid').text()) + '">' +
$(data).find('name').text().htmlEnc() +
'</option>';
}
}
// Generate specific HTML code
var favorites_bubble = '<option value="none" class="gc-join-first-option" selected="">' + Common._e("Select a favorite") + '</option>' + html;
var favorites_popup = '<option value="none" class="fedit-head-select-first-option" selected="">' + Common._e("Select a favorite") + '</option>' + html;
var favorites_bubble = '<option value="none" class="gc-join-first-option" selected="">' +
Common._e("Select a favorite") +
'</option>' + html;
var favorites_popup = '<option value="none" class="fedit-head-select-first-option" selected="">' +
Common._e("Select a favorite") +
'</option>' + html;
// Append the HTML code
$('#roster .buddy-conf-groupchat-select').html(favorites_bubble);
@ -647,29 +709,31 @@ var Favorites = (function () {
self.instance = function() {
try {
var path = '#favorites .';
var favorites_sel = $('#favorites');
// Keyboard events
$(path + 'fsearch-head-server').keyup(function(e) {
favorites_sel.find('.fsearch-head-server').keyup(function(e) {
if(e.keyCode == 13) {
var this_sel = $(this);
// No value?
if(!$(this).val())
$(this).val(HOST_MUC);
if(!this_sel.val()) {
this_sel.val(HOST_MUC);
}
// Get the list
self.getGCList();
}
});
$(path + 'fedit-line input').keyup(function(e) {
favorites_sel.find('.fedit-line input').keyup(function(e) {
if(e.keyCode == 13) {
// Edit a favorite
if($(path + 'fedit-edit').is(':visible'))
if(favorites_sel.find('.fedit-edit').is(':visible')) {
self.terminateThis('edit');
// Add a favorite
else
} else {
self.terminateThis('add');
}
}
});
@ -677,33 +741,33 @@ var Favorites = (function () {
$('.fedit-head-select').change(self.edit);
// Click events
$(path + 'room-switcher').click(function() {
$(path + 'favorites-content').hide();
favorites_sel.find('.room-switcher').click(function() {
favorites_sel.find('.favorites-content').hide();
self.reset();
});
$(path + 'room-list').click(function() {
$(path + 'favorites-edit').show();
favorites_sel.find('.room-list').click(function() {
favorites_sel.find('.favorites-edit').show();
});
$(path + 'room-search').click(function() {
$(path + 'favorites-search').show();
favorites_sel.find('.room-search').click(function() {
favorites_sel.find('.favorites-search').show();
self.getGCList();
});
$(path + 'fedit-add').click(function() {
favorites_sel.find('.fedit-add').click(function() {
return self.terminateThis('add');
});
$(path + 'fedit-edit').click(function() {
favorites_sel.find('.fedit-edit').click(function() {
return self.terminateThis('edit');
});
$(path + 'fedit-remove').click(function() {
favorites_sel.find('.fedit-remove').click(function() {
return self.terminateThis('remove');
});
$(path + 'bottom .finish').click(function() {
favorites_sel.find('.bottom .finish').click(function() {
return self.quit();
});
} catch(e) {

View file

@ -103,7 +103,7 @@ var Features = (function () {
};
// Markers
var namespaces = [NS_PUBSUB, NS_PUBSUB_CN, NS_URN_MAM, NS_COMMANDS, NS_URN_CARBONS];
var namespaces = [NS_PUBSUB, NS_PUBSUB_CN, NS_URN_MAM, NS_COMMANDS, NS_URN_CARBONS, NS_URN_CORRECT];
var identity = selector.find('identity');
@ -218,6 +218,11 @@ var Features = (function () {
if(self.enabledMAMPurge()) {
$(path + 'mam-purge-hidable').show();
}
// Message correction features
if(self.enabledCorrection()) {
$(path + 'correction-hidable').show();
}
// Commands features
if(self.enabledCommands()) {
@ -385,6 +390,22 @@ var Features = (function () {
};
/**
* Returns the XMPP server correction support
* @public
* @return {boolean}
*/
self.enabledCorrection = function() {
try {
return self.isEnabled(NS_URN_CORRECT);
} catch(e) {
Console.error('Features.enabledCorrection', e);
}
};
/**
* Normalizes the XMPP server name
* @private

View file

@ -20,6 +20,300 @@ var Filter = (function () {
var self = {};
/* Constants */
self.message_regex = {
'commands': {
'me': /((^)|((.+)(>)))(\/me )([^<]+)/
},
'emotes': {
'angry': [
/(:-?@)($|\s|<)/gi,
'$2'
],
'bat': [
/(:-?\[)($|\s|<)/gi,
'$2'
],
'beer': [
/(\(B\))($|\s|<)/g,
'$2'
],
'biggrin': [
/((:-?D)|(XD))($|\s|<)/gi,
'$4'
],
'blush': [
/(:-?\$)($|\s|<)/gi,
'$2'
],
'boy': [
/(\(Z\))($|\s|<)/g,
'$2'
],
'brflower': [
/(\(W\))($|\s|<)/g,
'$2'
],
'brheart': [
/((&lt;\/3)|(\(U\)))($|\s|<)/g,
'$4'
],
'coffee': [
/(\(C\))($|\s|<)/g,
'$2'
],
'coolglasses': [
/((8-\))|(\(H\)))($|\s|<)/g,
'$4'
],
'cry': [
/(:'-?\()($|\s|<)/gi,
'$2'
],
'cuffs': [
/(\(%\))($|\s|<)/g,
'$2'
],
'devil': [
/(\]:-?&gt;)($|\s|<)/gi,
'$2'
],
'drink': [
/(\(D\))($|\s|<)/g,
'$2'
],
'flower': [
/(@}-&gt;--)($|\s|<)/gi,
'$2'
],
'frowning': [
/((:-?\/)|(:-?S))($|\s|<)/gi,
'$4'
],
'girl': [
/(\(X\))($|\s|<)/g,
'$2'
],
'heart': [
/((&lt;3)|(\(L\)))($|\s|<)/g,
'$4'
],
'hugleft': [
/(\(}\))($|\s|<)/g,
'$2'
],
'hugright': [
/(\({\))($|\s|<)/g,
'$2'
],
'kis': [
/(:-?{})($|\s|<)/gi,
'$2'
],
'lamp': [
/(\(I\))($|\s|<)/g,
'$2'
],
'lion': [
/(:-?3)($|\s|<)/gi,
'$2'
],
'mail': [
/(\(E\))($|\s|<)/g,
'$2'
],
'moon': [
/(\(S\))($|\s|<)/g,
'$2'
],
'music': [
/(\(8\))($|\s|<)/g,
'$2'
],
'oh': [
/((=-?O)|(:-?O))($|\s|<)/gi,
'$4'
],
'phone': [
/(\(T\))($|\s|<)/g,
'$2'
],
'photo': [
/(\(P\))($|\s|<)/g,
'$2'
],
'puke': [
/(:-?!)($|\s|<)/gi,
'$2'
],
'pussy': [
/(\(@\))($|\s|<)/g,
'$2'
],
'rainbow': [
/(\(R\))($|\s|<)/g,
'$2'
],
'smile': [
/(:-?\))($|\s|<)/gi,
'$2'
],
'star': [
/(\(\*\))($|\s|<)/g,
'$2'
],
'stare': [
/(:-?\|)($|\s|<)/gi,
'$2'
],
'thumbdown': [
/(\(N\))($|\s|<)/g,
'$2'
],
'thumbup': [
/(\(Y\))($|\s|<)/g,
'$2'
],
'tongue': [
/(:-?P)($|\s|<)/gi,
'$2'
],
'unhappy': [
/(:-?\()($|\s|<)/gi,
'$2'
],
'wink': [
/(;-?\))($|\s|<)/gi,
'$2'
]
},
'formatting': {
'bold': [
/(^|\s|>|\()((\*)([^<>'"\*]+)(\*))($|\s|<|\))/gi,
'$1<b>$2</b>$6'
],
'italic': [
/(^|\s|>|\()((\/)([^<>'"\/]+)(\/))($|\s|<|\))/gi,
'$1<em>$2</em>$6'
],
'underline': [
/(^|\s|>|\()((_)([^<>'"_]+)(_))($|\s|<|\))/gi,
'$1<span style="text-decoration: underline;">$2</span>$6'
]
}
};
self.xhtml_allow = {
'elements': [
'a',
'abbr',
'acronym',
'address',
'blockquote',
'body',
'br',
'cite',
'code',
'dd',
'dfn',
'div',
'dt',
'em',
'h1',
'h2',
'h3',
'h4',
'h5',
'h6',
'head',
'html',
'kbd',
'li',
'ol',
'p',
'pre',
'q',
'samp',
'span',
'strong',
'title',
'ul',
'var'
],
'attributes': [
'accesskey',
'alt',
'charset',
'cite',
'class',
'height',
'href',
'hreflang',
'id',
'longdesc',
'profile',
'rel',
'rev',
'src',
'style',
'tabindex',
'title',
'type',
'uri',
'version',
'width',
'xml:lang',
'xmlns'
]
};
/**
* Generates a given emoticon HTML code
* @public
@ -42,83 +336,64 @@ var Filter = (function () {
/**
* Filters a given message
* @public
* @param {string} neutralMessage
* @param {string} message
* @param {string} nick
* @param {string} html_escape
* @return {string}
*/
self.message = function(neutralMessage, nick, html_escape) {
self.message = function(message, nick, html_escape) {
try {
var filteredMessage = neutralMessage;
var filtered = message;
// We encode the HTML special chars
if(html_escape)
filteredMessage = filteredMessage.htmlEnc();
// /me command
filteredMessage = filteredMessage.replace(/((^)|((.+)(>)))(\/me )([^<]+)/, nick + ' $7')
// We replace the smilies text into images
.replace(/(:-?@)($|\s|<)/gi, self.emoteImage('angry', '$1', '$2'))
.replace(/(:-?\[)($|\s|<)/gi, self.emoteImage('bat', '$1', '$2'))
.replace(/(\(B\))($|\s|<)/g, self.emoteImage('beer', '$1', '$2'))
.replace(/((:-?D)|(XD))($|\s|<)/gi, self.emoteImage('biggrin', '$1', '$4'))
.replace(/(:-?\$)($|\s|<)/gi, self.emoteImage('blush', '$1', '$2'))
.replace(/(\(Z\))($|\s|<)/g, self.emoteImage('boy', '$1', '$2'))
.replace(/(\(W\))($|\s|<)/g, self.emoteImage('brflower', '$1', '$2'))
.replace(/((&lt;\/3)|(\(U\)))($|\s|<)/g, self.emoteImage('brheart', '$1', '$4'))
.replace(/(\(C\))($|\s|<)/g, self.emoteImage('coffee', '$1', '$2'))
.replace(/((8-\))|(\(H\)))($|\s|<)/g, self.emoteImage('coolglasses', '$1', '$4'))
.replace(/(:'-?\()($|\s|<)/gi, self.emoteImage('cry', '$1', '$2'))
.replace(/(\(%\))($|\s|<)/g, self.emoteImage('cuffs', '$1', '$2'))
.replace(/(\]:-?&gt;)($|\s|<)/gi, self.emoteImage('devil', '$1', '$2'))
.replace(/(\(D\))($|\s|<)/g, self.emoteImage('drink', '$1', '$2'))
.replace(/(@}-&gt;--)($|\s|<)/gi, self.emoteImage('flower', '$1', '$2'))
.replace(/((:-?\/)|(:-?S))($|\s|<)/gi, self.emoteImage('frowning', '$1', '$4'))
.replace(/(\(X\))($|\s|<)/g, self.emoteImage('girl', '$1', '$2'))
.replace(/((&lt;3)|(\(L\)))($|\s|<)/g, self.emoteImage('heart', '$1', '$4'))
.replace(/(\(}\))($|\s|<)/g, self.emoteImage('hugleft', '$1', '$2'))
.replace(/(\({\))($|\s|<)/g, self.emoteImage('hugright', '$1', '$2'))
.replace(/(:-?{})($|\s|<)/gi, self.emoteImage('kiss', '$1', '$2'))
.replace(/(\(I\))($|\s|<)/g, self.emoteImage('lamp', '$1', '$2'))
.replace(/(:-?3)($|\s|<)/gi, self.emoteImage('lion', '$1', '$2'))
.replace(/(\(E\))($|\s|<)/g, self.emoteImage('mail', '$1', '$2'))
.replace(/(\(S\))($|\s|<)/g, self.emoteImage('moon', '$1', '$2'))
.replace(/(\(8\))($|\s|<)/g, self.emoteImage('music', '$1', '$2'))
.replace(/((=-?O)|(:-?O))($|\s|<)/gi, self.emoteImage('oh', '$1', '$4'))
.replace(/(\(T\))($|\s|<)/g, self.emoteImage('phone', '$1', '$2'))
.replace(/(\(P\))($|\s|<)/g, self.emoteImage('photo', '$1', '$2'))
.replace(/(:-?!)($|\s|<)/gi, self.emoteImage('puke', '$1', '$2'))
.replace(/(\(@\))($|\s|<)/g, self.emoteImage('pussy', '$1', '$2'))
.replace(/(\(R\))($|\s|<)/g, self.emoteImage('rainbow', '$1', '$2'))
.replace(/(:-?\))($|\s|<)/gi, self.emoteImage('smile', '$1', '$2'))
.replace(/(\(\*\))($|\s|<)/g, self.emoteImage('star', '$1', '$2'))
.replace(/(:-?\|)($|\s|<)/gi, self.emoteImage('stare', '$1', '$2'))
.replace(/(\(N\))($|\s|<)/g, self.emoteImage('thumbdown', '$1', '$2'))
.replace(/(\(Y\))($|\s|<)/g, self.emoteImage('thumbup', '$1', '$2'))
.replace(/(:-?P)($|\s|<)/gi, self.emoteImage('tongue', '$1', '$2'))
.replace(/(:-?\()($|\s|<)/gi, self.emoteImage('unhappy', '$1', '$2'))
.replace(/(;-?\))($|\s|<)/gi, self.emoteImage('wink', '$1', '$2'))
// Text in bold
.replace(/(^|\s|>|\()((\*)([^<>'"\*]+)(\*))($|\s|<|\))/gi, '$1<b>$2</b>$6')
// Italic text
.replace(/(^|\s|>|\()((\/)([^<>'"\/]+)(\/))($|\s|<|\))/gi, '$1<em>$2</em>$6')
// Underlined text
.replace(/(^|\s|>|\()((_)([^<>'"_]+)(_))($|\s|<|\))/gi, '$1<span style="text-decoration: underline;">$2</span>$6');
// Add the links
if(html_escape) {
filteredMessage = Links.apply(filteredMessage, 'desktop');
filtered = filtered.htmlEnc();
}
// Filter integratebox links
filteredMessage = IntegrateBox.filter(filteredMessage);
// Security: don't filter huge messages (avoids crash attacks)
if(filtered.length < 10000) {
// /me command
filtered = filtered.replace(self.message_regex.commands.me, nick + ' $7');
// We replace the smilies text into images
var cur_emote;
for(var cur_emote_name in self.message_regex.emotes) {
cur_emote = self.message_regex.emotes[cur_emote_name];
filtered = filtered.replace(
cur_emote[0],
self.emoteImage(
cur_emote_name,
'$1',
cur_emote[1]
)
);
}
// Text formatting
var cur_formatting;
for(var cur_formatting_name in self.message_regex.formatting) {
cur_formatting = self.message_regex.formatting[cur_formatting_name];
filtered = filtered.replace(
cur_formatting[0],
cur_formatting[1]
);
}
// Add the links
if(html_escape) {
filtered = Links.apply(filtered, 'desktop');
}
// Filter integratebox links
filtered = IntegrateBox.filter(filtered);
}
return filteredMessage;
return filtered;
} catch(e) {
Console.error('Filter.message', e);
}
@ -135,85 +410,23 @@ var Filter = (function () {
self.xhtml = function(code) {
try {
// Allowed elements array
var elements = new Array(
'a',
'abbr',
'acronym',
'address',
'blockquote',
'body',
'br',
'cite',
'code',
'dd',
'dfn',
'div',
'dt',
'em',
'h1',
'h2',
'h3',
'h4',
'h5',
'h6',
'head',
'html',
'kbd',
'li',
'ol',
'p',
'pre',
'q',
'samp',
'span',
'strong',
'title',
'ul',
'var'
);
var code_sel = $(code);
// Allowed attributes array
var attributes = new Array(
'accesskey',
'alt',
'charset',
'cite',
'class',
'height',
'href',
'hreflang',
'id',
'longdesc',
'profile',
'rel',
'rev',
'src',
'style',
'tabindex',
'title',
'type',
'uri',
'version',
'width',
'xml:lang',
'xmlns'
);
// Check if Filter for XHTML-IM images is enabled
if(DataStore.getDB(Connection.desktop_hash, 'options', 'no-xhtml-images') != '1') {
elements.push("img");
self.xhtml_allow.elements.push("img");
}
// Remove forbidden elements
$(code).find('html body *').each(function() {
code_sel.find('html body *').each(function() {
// This element is not authorized
if(!Utils.existArrayValue(elements, (this).nodeName.toLowerCase()))
if(!Utils.existArrayValue(self.xhtml_allow.elements, (this).nodeName.toLowerCase())) {
$(this).remove();
}
});
// Remove forbidden attributes
$(code).find('html body *').each(function() {
code_sel.find('html body *').each(function() {
// Put a pointer on this element (jQuery way & normal way)
var cSelector = $(this);
var cElement = (this);
@ -226,15 +439,17 @@ var Filter = (function () {
var cVal = cAttr.value;
// This attribute is not authorized, or contains JS code
if(!Utils.existArrayValue(attributes, cName.toLowerCase()) || ((cVal.toLowerCase()).match(/(^|"|')javascript:/)))
if(!Utils.existArrayValue(self.xhtml_allow.attributes, cName.toLowerCase()) ||
((cVal.toLowerCase()).match(/(^|"|')javascript:/))) {
cSelector.removeAttr(cName);
}
});
});
// Filter some other elements
$(code).find('a').attr('target', '_blank');
code_sel.find('a').attr('target', '_blank');
return $(code).find('html body').html();
return code_sel.find('html body').html();
} catch(e) {
Console.error('Filter.xhtml', e);
}

View file

@ -24,6 +24,196 @@ var Groupchat = (function () {
var JOIN_SUGGEST = [];
/**
* Apply generate events
* @private
* @param {object} input_sel
* @param {string} hash
* @param {string} room
* @return {undefined}
*/
self._createEvents = function(input_sel, hash, room) {
try {
self._createEventsInput(input_sel, hash);
self._createEventsKey(input_sel, hash, room);
} catch(e) {
Console.error('Groupchat._createEvents', e);
}
};
/**
* Apply generate events (input)
* @private
* @param {object} input_sel
* @param {string} hash
* @return {undefined}
*/
self._createEventsInput = function(input_sel, hash) {
try {
// Focus event
input_sel.focus(function() {
// Clean notifications for this chat
Interface.chanCleanNotify(hash);
// Store focus on this chat!
Interface.chat_focus_hash = hash;
});
// Blur event
input_sel.blur(function() {
// Reset storage about focus on this chat!
if(Interface.chat_focus_hash == hash) {
Interface.chat_focus_hash = null;
}
// Reset autocompletion
Autocompletion.reset(hash);
});
} catch(e) {
Console.error('Groupchat._createEventsInput', e);
}
};
/**
* Apply generate events (key)
* @private
* @param {object} input_sel
* @param {string} hash
* @param {string} room
* @return {undefined}
*/
self._createEventsKey = function(input_sel, hash, room) {
try {
// Lock to the input
input_sel.keydown(function(e) {
// Enter key
if(e.keyCode == 13) {
// If shift key (without any others modifiers) was pressed, add a new line
if(e.shiftKey && !e.ctrlKey && !e.altKey && !e.metaKey) {
input_sel.val(input_sel.val() + '\n');
} else {
if(Correction.isIn(room) === true) {
var corrected_value = input_sel.val().trim();
if(corrected_value) {
// Send the corrected message
Correction.send(room, 'groupchat', corrected_value);
}
Correction.leave(room);
} else {
// Send the message
Message.send(hash, 'groupchat');
// Reset the composing database entry
DataStore.setDB(Connection.desktop_hash, 'chatstate', room, 'off');
}
}
return false;
}
// Remove chars (leave correction)
else if(e.keyCode == 8) {
// Leave correction mode? (another way, by flushing input value progressively)
if(Correction.isIn(room) === true && !input_sel.val()) {
Correction.leave(room);
}
}
// Tabulation key (without any modifiers)
else if(!e.shiftKey && !e.ctrlKey && !e.altKey && !e.metaKey && e.keyCode == 9) {
Autocompletion.create(hash);
return false;
}
// Reset the autocompleter
else {
Autocompletion.reset(hash);
}
});
input_sel.keyup(function(e) {
if(e.keyCode == 27) {
// Escape key
input_sel.val('');
// Leave correction mode? (simple escape way)
if(Correction.isIn(room) === true) {
Correction.leave(room);
}
} else {
Correction.detect(room, input_sel);
}
});
} catch(e) {
Console.error('Groupchat._createEventsKey', e);
}
};
/**
* Apply suggest check events
* @private
* @return {undefined}
*/
self._suggestCheckEvents = function() {
try {
// Click events
$('#suggest .content a.one').click(function() {
var this_sel = $(this);
// Add/remove the active class
this_sel.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() {
var this_sel = $(this);
// Disabled?
if(this_sel.hasClass('disabled')) {
return false;
}
// Store groupchats to join?
if(this_sel.is('.continue')) {
$('#suggest .content a.one.active').each(function() {
JOIN_SUGGEST.push(this_sel.attr('data-xid'));
});
}
// Switch to talk UI
$('#suggest').remove();
Connection.triggerConnected();
return false;
});
} catch(e) {
Console.error('Groupchat._suggestCheckEvents', e);
}
};
/**
* Displays the MUC admin elements
* @public
@ -37,16 +227,19 @@ var Groupchat = (function () {
try {
// We must be in the "login" mode
if(Utils.isAnonymous())
if(Utils.isAnonymous()) {
return;
}
// We check if the user is a room owner or administrator to give him privileges
if(affiliation == 'owner' || affiliation == 'admin')
if(affiliation == 'owner' || affiliation == 'admin') {
$('#' + id + ' .tools-mucadmin').show();
}
// We check if the room hasn't been yet created
if(statuscode == 201)
if(statuscode == 201) {
Board.openThisInfo(4);
}
// We add the click event
$('#' + id + ' .tools-mucadmin').click(function() {
@ -80,14 +273,16 @@ var Groupchat = (function () {
// No nickname?
if(!nickname) {
// Get some values
if(!Utils.isAnonymous())
if(!Utils.isAnonymous()) {
nickname = Name.getNick();
else
} else {
nickname = ANONYMOUS_NICK;
}
// If the nickname could not be retrieved, ask it
if(!nickname)
if(!nickname) {
self.generateMUCAsk('nickname', room, hash, nickname, password);
}
}
// Got our nickname?
@ -126,10 +321,12 @@ var Groupchat = (function () {
var room = Common.bareXID(from);
var nickname = Common.thisResource(from);
var hash = hex_md5(room);
var id = presence.getID();
// No ID: must fix M-Link bug
if(presence.getID() === null) {
presence.setID(1);
if(id === null) {
id = 1;
presence.setID(id);
}
Console.info('First MUC presence: ' + from);
@ -139,11 +336,17 @@ var Groupchat = (function () {
// Define some stuffs
var muc_user = $(xml).find('x[xmlns="' + NS_MUC_USER + '"]');
var affiliation = muc_user.find('item').attr('affiliation');
var statuscode = parseInt(muc_user.find('status').attr('code'));
var statuscode = parseInt(muc_user.find('status').attr('code'));
// Handle my presence
Presence.handle(presence);
// Configure the new room
if(affiliation == 'owner' || affiliation == 'admin') {
console.debug('presence', presence.xml());
self._initialConfiguration(id, room);
}
// Check if I am a room owner
self.openAdmin(affiliation, hash, room, statuscode);
@ -279,65 +482,16 @@ var Groupchat = (function () {
});
// Must show the add button?
if(!DataStore.existDB('favorites', room))
if(!DataStore.existDB(Connection.desktop_hash, 'favorites', room)) {
$('#' + hash + ' .tools-add').show();
}
// The event handlers
var inputDetect = $('#' + hash + ' .message-area');
// Focus event
inputDetect.focus(function() {
// Clean notifications for this chat
Interface.chanCleanNotify(hash);
// Store focus on this chat!
Interface.chat_focus_hash = hash;
});
// Blur event
inputDetect.blur(function() {
// Reset storage about focus on this chat!
if(Interface.chat_focus_hash == hash)
Interface.chat_focus_hash = null;
// Reset autocompletion
Autocompletion.reset(hash);
});
// Lock to the input
inputDetect.keydown(function(e) {
// Enter key
if(e.keyCode == 13) {
// If shift key (without any others modifiers) was pressed, add a new line
if(e.shiftKey && !e.ctrlKey && !e.altKey && !e.metaKey)
inputDetect.val(inputDetect.val() + '\n');
// Send the message
else {
Message.send(hash, 'groupchat');
// Reset the composing database entry
DataStore.setDB(Connection.desktop_hash, 'chatstate', room, 'off');
}
return false;
}
// Tabulation key (without any modifiers)
else if(!e.shiftKey && !e.ctrlKey && !e.altKey && !e.metaKey && e.keyCode == 9) {
Autocompletion.create(hash);
return false;
}
// Reset the autocompleter
else {
Autocompletion.reset(hash);
}
});
var input_sel = $('#' + hash + ' .message-area');
self._createEvents(input_sel, hash, room);
// Chatstate events
ChatState.events(inputDetect, room, hash, 'groupchat');
ChatState.events(input_sel, room, hash, 'groupchat');
// Get the current muc informations and content
self.getMUC(room, nickname, password);
@ -361,23 +515,26 @@ var Groupchat = (function () {
var new_arr = [];
// Try to split it
if(GROUPCHATS_JOIN.indexOf(',') != -1)
if(GROUPCHATS_JOIN.indexOf(',') != -1) {
muc_arr = GROUPCHATS_JOIN.split(',');
}
for(var i in muc_arr) {
// Get the current value
var muc_current = $.trim(muc_arr[i]);
// No current value?
if(!muc_current)
if(!muc_current) {
continue;
}
// Filter the current value
muc_current = Common.generateXID(muc_current, 'groupchat');
// Add the current value
if(!Utils.existArrayValue(new_arr, muc_current))
if(!Utils.existArrayValue(new_arr, muc_current)) {
new_arr.push(muc_current);
}
}
return new_arr;
@ -397,8 +554,9 @@ var Groupchat = (function () {
try {
// Nothing to join?
if(!JOIN_SUGGEST)
if(!JOIN_SUGGEST) {
return;
}
// Join the chats
if(JOIN_SUGGEST.length) {
@ -425,8 +583,9 @@ var Groupchat = (function () {
// Must suggest the user?
if((GROUPCHATS_SUGGEST == 'on') && groupchat_arr.length) {
if(Common.exists('#suggest'))
if(Common.exists('#suggest')) {
return;
}
// Create HTML code
var html = '<div id="suggest" class="removable">';
@ -452,39 +611,8 @@ var Groupchat = (function () {
// 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;
@ -512,7 +640,7 @@ 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();
@ -520,10 +648,16 @@ var Groupchat = (function () {
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);
@ -561,10 +695,16 @@ var Groupchat = (function () {
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);
@ -670,6 +810,50 @@ 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);
}
};
/**
@ -677,4 +861,4 @@ var Groupchat = (function () {
*/
return self;
})();
})();

View file

@ -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(
'<div class="obsolete">' +
'<p>' + Common._e("Your browser is out of date!") + '</p>' +
'<a class="firefox browsers-images" title="' + Common.printf(Common._e("Last %s version is better!"), 'Mozilla Firefox') + '" href="http://www.mozilla.com/firefox/"></a>' +
'<a class="chrome browsers-images" title="' + Common.printf(Common._e("Last %s version is better!"), 'Google Chrome') + '" href="http://www.google.com/chrome"></a>' +
'<a class="safari browsers-images" title="' + Common.printf(Common._e("Last %s version is better!"), 'Safari') + '" href="http://www.apple.com/safari/"></a>' +
'<a class="opera browsers-images" title="' + Common.printf(Common._e("Last %s version is better!"), 'Opera') + '" href="http://www.opera.com/"></a>' +
'<a class="ie browsers-images" title="' + Common.printf(Common._e("Last %s version is better!"), 'Internet Explorer') + '" href="http://www.microsoft.com/hk/windows/internet-explorer/"></a>' +
'</div>'
);
// 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
@ -76,7 +189,7 @@ var Home = (function () {
'<legend>' + Common._e("Required") + '</legend>' +
'<label for="lnick">' + Common._e("Address") + '</label>' +
'<input type="text" class="nick" id="lnick" pattern="[^@/]+" required="" /><span class="jid">@</span><input type="text" class="server" id="lserver" value="' + HOST_MAIN + '" ' + lock_host + ' pattern="[^@/]+" required="" />' +
'<input type="text" class="nick" id="lnick" pattern="[^@/]+" required="" /><span class="jid">@</span><input type="text" class="server" id="lserver" value="' + HOST_MAIN + '" ' + lock_host + ' pattern="[^@/]+" required="" list="server" />' +
'<label for="lpassword">' + Common._e("Password") + '</label>' +
'<input type="password" class="password" id="lpassword" required="" />' +
'<label for="lremember">' + Common._e("Remember me") + '</label>' +
@ -112,8 +225,9 @@ var Home = (function () {
disable_form = Utils.disableInput(ANONYMOUS, 'off');
code = '<p>' + 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."), '<a href="#" class="to-home">' + Common._e("login page") + '</a>') + '</p>';
if(LEGAL)
if(LEGAL) {
code += '<p>' + Common.printf(Common._e("By using our service, you accept %s."), '<b><a href="' + Common.encodeQuotes(LEGAL) + '" target="_blank">' + Common._e("our terms of use") + '</a></b>') + '</p>';
}
code += '<form action="#" method="post">' +
'<fieldset>' +
@ -139,27 +253,30 @@ var Home = (function () {
case 'registerer':
disable_form = Utils.disableInput(REGISTRATION, 'off');
if(!disable_form)
if(!disable_form) {
lock_host = Utils.disableInput(LOCK_HOST, 'on');
}
code = '<p>' + Common._e("Register a new XMPP account to join your friends on your own social cloud. That's simple!") + '</p>';
if(LEGAL)
if(LEGAL) {
code += '<p>' + Common.printf(Common._e("By using our service, you accept %s."), '<b><a href="' + Common.encodeQuotes(LEGAL) + '" target="_blank">' + Common._e("our terms of use") + '</a></b>') + '</p>';
}
code += '<form action="#" method="post">' +
'<fieldset>' +
'<legend>' + Common._e("Required") + '</legend>' +
'<label for="rnick">' + Common._e("Address") + '</label>' +
'<input type="text" class="nick" id="rnick" ' + disable_form + ' pattern="[^@/]+" required="" placeholder="' + Common._e("Username") + '" /><span class="jid">@</span><input type="text" class="server" id="rserver" value="' + HOST_MAIN + '" ' + disable_form + lock_host + ' pattern="[^@/]+" required="" placeholder="' + Common._e("Server") + '" />' +
'<input type="text" class="nick" id="rnick" ' + disable_form + ' pattern="[^@/]+" required="" placeholder="' + Common._e("Username") + '" /><span class="jid">@</span><input type="text" class="server" id="rserver" value="' + HOST_MAIN + '" ' + disable_form + lock_host + ' pattern="[^@/]+" required="" list="server" placeholder="' + Common._e("Server") + '" />' +
'<label for="rpassword">' + Common._e("Password") + '</label>' +
'<input type="password" class="password" id="rpassword" ' + disable_form + ' required="" placeholder="' + Common._e("Enter password") + '" /><input type="password" class="spassword" id="spassword" ' + disable_form + ' required="" placeholder="' + Common._e("Once again...") + '" />';
if(REGISTER_API == 'on')
if(REGISTER_API == 'on') {
code += '<div class="captcha_grp">' +
'<label for="captcha">' + Common._e("Code") + '</label><input type="text" class="captcha" id="captcha" ' + disable_form + ' maxlength="6" pattern="[a-zA-Z0-9]{6}" required="" placeholder="' + Common._e("Security code") + '" /><img class="captcha_img" src="./server/captcha.php?id=' + genID() + '" alt="" />' +
'</div>';
}
code += '</fieldset>' +
@ -170,78 +287,22 @@ var Home = (function () {
}
// Form disabled?
if(disable_form)
if(disable_form) {
code += '<div class="info fail">' +
Common._e("This tool has been disabled!") +
'</div>';
}
// Create this HTML code
if(code && !Common.exists(current)) {
// Append it!
$(right + '.homediv.default').after('<div class="' + div + ' homediv">' + code + '</div>');
$(right + '.homediv.default').after(
'<div class="' + div + ' homediv">' + code + '</div>'
);
// Create the attached events
switch(div) {
// Login tool
case 'loginer':
$(current + ' a.to-anonymous').click(function() {
return self.change('anonymouser');
});
$(current + ' a.advanced').click(self.showAdvanced);
$(current + ' form').submit(self.loginForm);
break;
// Anonymous login tool
case 'anonymouser':
$(current + ' a.to-home').click(function() {
return self.change('loginer');
});
$(current + ' form').submit(Connection.doAnonymous);
// Keyup event on anonymous join's room input
$(current + ' input.room').keyup(function() {
var value = $(this).val();
var report = current + ' .report';
var span = report + ' span';
if(!value) {
$(report).hide();
$(span).text('');
}
else {
$(report).show();
$(span).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 + ' form').submit(self.registerForm);
break;
}
self._eventsChange(
$(current),
div
);
}
// We focus on the first input
@ -288,13 +349,14 @@ var Home = (function () {
try {
// We get the values
var lPath = '#home .loginer ';
var lServer = $(lPath + '.server').val();
var lNick = Common.nodeprep($(lPath + '.nick').val());
var lPass = $(lPath + '.password').val();
var lResource = $(lPath + '.resource').val();
var lPriority = $(lPath + '.priority').val();
var lRemember = $(lPath + '.remember').filter(':checked').size();
var path_sel = $('#home .loginer');
var lServer = path_sel.find('.server').val();
var lNick = Common.nodeprep(path_sel.find('.nick').val());
var lPass = path_sel.find('.password').val();
var lResource = path_sel.find('.resource').val();
var lPriority = path_sel.find('.priority').val();
var lRemember = path_sel.find('.remember').filter(':checked').size();
// Enough values?
if(lServer && lNick && lPass && lResource && lPriority) {
@ -303,12 +365,13 @@ var Home = (function () {
$(lPath + 'input[type="text"], ' + lPath + 'input[type="password"]').each(function() {
var select = $(this);
if(!select.val())
if(!select.val()) {
$(document).oneTime(10, function() {
select.addClass('please-complete').focus();
});
else
} else {
select.removeClass('please-complete');
}
});
}
} catch(e) {
@ -328,17 +391,18 @@ var Home = (function () {
self.registerForm = function() {
try {
var rPath = '#home .registerer ';
var path = '#home .registerer';
var path_sel = $(path);
// Remove the success info
$(rPath + '.success').remove();
path_sel.find('.success').remove();
// Get the values
var username = Common.nodeprep($(rPath + '.nick').val());
var domain = $(rPath + '.server').val();
var pass = $(rPath + '.password').val();
var spass = $(rPath + '.spassword').val();
var captcha = $(rPath + '.captcha').val();
var username = Common.nodeprep(path_sel.find('.nick').val());
var domain = path_sel.find('.server').val();
var pass = path_sel.find('.password').val();
var spass = path_sel.find('.spassword').val();
var captcha = path_sel.find('.captcha').val();
// Enough values?
if(domain && username && pass && spass && (pass == spass) && !((REGISTER_API == 'on') && (domain == HOST_MAIN) && !captcha)) {
@ -351,15 +415,16 @@ var Home = (function () {
// Something is missing?
else {
$(rPath + 'input[type="text"], ' + rPath + 'input[type="password"]').each(function() {
$(path + ' input[type="text"], ' + path + ' input[type="password"]').each(function() {
var select = $(this);
if(!select.val() || (select.is('#spassword') && pass && (pass != spass)))
if(!select.val() || (select.is('#spassword') && pass && (pass != spass))) {
$(document).oneTime(10, function() {
select.addClass('please-complete').focus();
});
else
} else {
select.removeClass('please-complete');
}
});
}
} catch(e) {
@ -394,12 +459,14 @@ var Home = (function () {
// Allows the user to switch the home page
$(button).click(function() {
// Login button
if($(this).is('.login'))
if($(this).is('.login')) {
return self.change('loginer');
}
// Register button
else
else {
return self.change('registerer');
}
});
// Allows the user to view the corporation & about infobox
@ -430,31 +497,14 @@ var Home = (function () {
// Disables the browser HTTP-requests stopper
$(document).keydown(function(e) {
if((e.keyCode == 27) && !System.isDeveloper())
if((e.keyCode == 27) && !System.isDeveloper()) {
return false;
}
});
// Warns for an obsolete browser
if(Utils.isObsolete()) {
// Add the code
$(locale).after(
'<div class="obsolete">' +
'<p>' + Common._e("Your browser is out of date!") + '</p>' +
'<a class="firefox browsers-images" title="' + Common.printf(Common._e("Last %s version is better!"), 'Mozilla Firefox') + '" href="http://www.mozilla.com/firefox/"></a>' +
'<a class="chrome browsers-images" title="' + Common.printf(Common._e("Last %s version is better!"), 'Google Chrome') + '" href="http://www.google.com/chrome"></a>' +
'<a class="safari browsers-images" title="' + Common.printf(Common._e("Last %s version is better!"), 'Safari') + '" href="http://www.apple.com/safari/"></a>' +
'<a class="opera browsers-images" title="' + Common.printf(Common._e("Last %s version is better!"), 'Opera') + '" href="http://www.opera.com/"></a>' +
'<a class="ie browsers-images" title="' + Common.printf(Common._e("Last %s version is better!"), 'Internet Explorer') + '" href="http://www.microsoft.com/hk/windows/internet-explorer/"></a>' +
'</div>'
);
// Display it later
$(home + '.obsolete').oneTime('1s', function() {
$(this).slideDown();
});
Console.warn('Jappix does not support this browser!');
self._obsolete();
}
Console.log('Welcome to Jappix! Happy coding in developer mode!');
@ -473,4 +523,4 @@ var Home = (function () {
})();
Home.launch();
Home.launch();

View file

@ -34,8 +34,6 @@ var HTTPAuth = (function () {
try {
// We add the login wait div
Interface.showGeneralWait();
oArgs = {};
if(Common.hasWebSocket()) {
// WebSocket supported & configured
@ -67,15 +65,6 @@ var HTTPAuth = (function () {
// Generate a priority
lPriority = lPriority ? lPriority : 10;
// We retrieve what the user typed in the login inputs
oArgs = {};
oArgs.domain = $.trim(lServer);
oArgs.username = $.trim(lNick);
oArgs.resource = random_resource;
oArgs.pass = lPass;
oArgs.secure = true;
oArgs.xmllang = XML_LANG;
// Store the resource (for reconnection)
DataStore.setDB(Connection.desktop_hash, 'session', 'resource', random_resource);
@ -89,7 +78,14 @@ var HTTPAuth = (function () {
DataStore.setDB(Connection.desktop_hash, 'priority', 1, 10);
// We connect !
con.connect(oArgs);
con.connect({
'domain': $.trim(lServer),
'username': $.trim(lNick),
'resource': random_resource,
'pass': lPass,
'secure': true,
'xmllang': XML_LANG
});
// Change the page title
Interface.title('wait');

View file

@ -45,11 +45,19 @@ var HTTPReply = (function () {
// If "no"
if(value == 'no') {
aMsg.setType('error');
aMsg.appendNode('error', {'code': '401', 'type': 'auth'});
aMsg.appendNode('error', {
'code': '401',
'type': 'auth'
});
}
// We set the confirm node
aMsg.appendNode('confirm', {'xmlns': xmlns, 'url': url, 'id': id, 'method': method});
aMsg.appendNode('confirm', {
'xmlns': xmlns,
'url': url,
'id': id,
'method': method
});
// We send the message
con.send(aMsg, Errors.handleReply);

View file

@ -176,17 +176,16 @@ var Inbox = (function () {
var value = $(Common.XMLFromString(DataStore.storageDB.getItem(current)));
// Create the storage node
storage.appendChild(iq.buildNode('message', {
'id': value.find('id').text().revertHtmlEnc(),
'from': value.find('from').text().revertHtmlEnc(),
'subject': value.find('subject').text().revertHtmlEnc(),
'status': value.find('status').text().revertHtmlEnc(),
'date': value.find('date').text().revertHtmlEnc(),
'xmlns': NS_INBOX
},
value.find('content').text().revertHtmlEnc()
));
storage.appendChild(
iq.buildNode('message', {
'id': value.find('id').text().revertHtmlEnc(),
'from': value.find('from').text().revertHtmlEnc(),
'subject': value.find('subject').text().revertHtmlEnc(),
'status': value.find('status').text().revertHtmlEnc(),
'date': value.find('date').text().revertHtmlEnc(),
'xmlns': NS_INBOX
}, value.find('content').text().revertHtmlEnc()
));
}
}
@ -207,18 +206,18 @@ var Inbox = (function () {
try {
// Init
var mPath = '#inbox .';
var inbox_sel = $('#inbox');
// Reset the previous buddy search
Search.resetBuddy('#inbox .inbox-new-to');
// We switch the divs
$(mPath + 'inbox-results, #inbox .a-new-message, #inbox .a-delete-messages').hide();
$(mPath + 'inbox-new, #inbox .a-show-messages').show();
inbox_sel.find('.inbox-results, .a-new-message, .a-delete-messages').hide();
inbox_sel.find('.inbox-new, .a-show-messages').show();
// We focus on the first input
$(document).oneTime(10, function() {
$(mPath + 'inbox-new-to-input').focus();
inbox_sel.find('.inbox-new-to-input').focus();
});
// We reset some stuffs
@ -241,16 +240,16 @@ var Inbox = (function () {
try {
// Init
var mPath = '#inbox .';
var inbox_sel = $('#inbox');
// We reset the forms
$(mPath + 'inbox-new-block:not(form) input, ' + mPath + 'inbox-new textarea').val('').removeClass('please-complete');
$(mPath + 'inbox-new-file a').remove();
$(mPath + 'inbox-new-file input').show();
inbox_sel.find('.inbox-new-block:not(form) input, .inbox-new textarea').val('').removeClass('please-complete');
inbox_sel.find('.inbox-new-file a').remove();
inbox_sel.find('.inbox-new-file input').show();
// We close an eventual opened message
$(mPath + 'message-content').remove();
$(mPath + 'one-message').removeClass('message-reading');
inbox_sel.find('.message-content').remove();
inbox_sel.find('.one-message').removeClass('message-reading');
} catch(e) {
Console.error('Inbox.cleanNewMessage', e);
}
@ -270,26 +269,26 @@ var Inbox = (function () {
try {
// We send the message
var mess = new JSJaCMessage();
var message = new JSJaCMessage();
// Main attributes
mess.setTo(to);
mess.setSubject(subject);
mess.setType('normal');
message.setTo(to);
message.setSubject(subject);
message.setType('normal');
// Any file to attach?
var attached = '#inbox .inbox-new-file a.file';
if(Common.exists(attached)) {
body += '\n' +
'\n' +
$(attached).attr('data-attachedtitle') + ' - ' + $(attached).attr('data-attachedhref');
'\n' +
$(attached).attr('data-attachedtitle') + ' - ' + $(attached).attr('data-attachedhref');
}
// Set body
mess.setBody(body);
message.setBody(body);
con.send(mess, Errors.handleReply);
con.send(message, Errors.handleReply);
} catch(e) {
Console.error('Inbox.sendMessage', e);
}
@ -306,10 +305,10 @@ var Inbox = (function () {
try {
// We get some informations
var mPath = '#inbox ';
var to = $(mPath + '.inbox-new-to-input').val();
var body = $(mPath + '.inbox-new-textarea').val();
var subject = $(mPath + '.inbox-new-subject-input').val();
var inbox_sel = $('#inbox');
var to = inbox_sel.find('.inbox-new-to-input').val();
var body = inbox_sel.find('.inbox-new-textarea').val();
var subject = inbox_sel.find('.inbox-new-subject-input').val();
if(to && body && subject) {
// New array of XID
@ -345,15 +344,15 @@ var Inbox = (function () {
}
else {
$(mPath + 'input[type="text"], ' + mPath + 'textarea').each(function() {
var current = this;
inbox_sel.find('input[type="text"], textarea').each(function() {
var this_sel = $(this);
if(!$(current).val()) {
if(!this_sel.val()) {
$(document).oneTime(10, function() {
$(current).addClass('please-complete').focus();
this_sel.addClass('please-complete').focus();
});
} else {
$(current).removeClass('please-complete');
this_sel.removeClass('please-complete');
}
});
}
@ -374,17 +373,16 @@ var Inbox = (function () {
self.showMessage = function() {
try {
// Init
var mPath = '#inbox .';
var inbox_sel = $('#inbox');
// We switch the divs
$(mPath + 'inbox-new').hide();
$(mPath + 'inbox-results').show();
inbox_sel.find('.inbox-new').hide();
inbox_sel.find('.inbox-results').show();
// We show a new link in the menu
$(mPath + 'a-show-messages').hide();
$(mPath + 'a-delete-messages').show();
$(mPath + 'a-new-message').show();
inbox_sel.find('.a-show-messages').hide();
inbox_sel.find('.a-delete-messages').show();
inbox_sel.find('.a-new-message').show();
// We reset some stuffs
self.cleanNewMessage();
@ -484,10 +482,14 @@ var Inbox = (function () {
try {
// Initialize the XML data
var xml = '<message><id>' + id.htmlEnc().htmlEnc() + '</id><date>' + date.htmlEnc().htmlEnc() + '</date><from>' + from.htmlEnc().htmlEnc() + '</from><subject>' + subject.htmlEnc().htmlEnc() + '</subject><status>' + status.htmlEnc().htmlEnc() + '</status><content>' + content.htmlEnc().htmlEnc() + '</content>';
// End the XML data
xml += '</message>';
var xml = '<message>' +
'<id>' + id.htmlEnc().htmlEnc() + '</id>' +
'<date>' + date.htmlEnc().htmlEnc() + '</date>' +
'<from>' + from.htmlEnc().htmlEnc() + '</from>' +
'<subject>' + subject.htmlEnc().htmlEnc() + '</subject>' +
'<status>' + status.htmlEnc().htmlEnc() + '</status>' +
'<content>' + content.htmlEnc().htmlEnc() + '</content>' +
'</message>';
// Store this message!
DataStore.setDB(Connection.desktop_hash, 'inbox', id, xml);
@ -504,7 +506,7 @@ var Inbox = (function () {
* @param {string} id
* @return {boolean}
*/
self.deleteMessage = function() {
self.deleteMessage = function(id) {
try {
// Remove the message from the inbox
@ -794,13 +796,13 @@ var Inbox = (function () {
// Display the current message
self.displayMessage(
value.find('from').text().revertHtmlEnc(),
value.find('subject').text().revertHtmlEnc(),
value.find('content').text().revertHtmlEnc(),
value.find('status').text().revertHtmlEnc(),
value.find('id').text().revertHtmlEnc(),
value.find('date').text().revertHtmlEnc()
);
value.find('from').text().revertHtmlEnc(),
value.find('subject').text().revertHtmlEnc(),
value.find('content').text().revertHtmlEnc(),
value.find('status').text().revertHtmlEnc(),
value.find('id').text().revertHtmlEnc(),
value.find('date').text().revertHtmlEnc()
);
}
}
@ -854,16 +856,30 @@ var Inbox = (function () {
// Hide the attach link, show the unattach one
$('#inbox .inbox-new-file input').hide();
$('#inbox .inbox-new-file').append('<a class="file ' + Common.encodeQuotes(Utils.fileCategory(Common.explodeThis('/', fType, 1))) + ' talk-images" href="' + Common.encodeQuotes(fURL) + '" target="_blank">' + fName.htmlEnc() + '</a><a href="#" class="remove one-button talk-images">' + Common._e("Remove") + '</a>');
$('#inbox .inbox-new-file').append(
'<a class="file ' + Common.encodeQuotes(Utils.fileCategory(Common.explodeThis('/', fType, 1))) + ' talk-images" ' +
'href="' + Common.encodeQuotes(fURL) + '" ' +
'target="_blank">' +
fName.htmlEnc() +
'</a>' +
'<a href="#" class="remove one-button talk-images">' +
Common._e("Remove") +
'</a>'
);
// Set values to the file link
$('#inbox .inbox-new-file a.file').attr('data-attachedtitle', fName)
.attr('data-attachedhref', fURL);
var inbox_file_sel = $('#inbox .inbox-new-file a.file');
inbox_file_sel.attr('data-attachedtitle', fName);
inbox_file_sel.attr('data-attachedhref', fURL);
// Click events
$('#inbox .inbox-new-file a.remove').click(function() {
$('#inbox .inbox-new-file a').remove();
$('#inbox .inbox-new-file input').show();
var inbox_new_file_sel = $('#inbox .inbox-new-file');
inbox_new_file_sel.find('a.remove').click(function() {
inbox_new_file_sel.find('a').remove();
inbox_new_file_sel.find('input').show();
return false;
});
@ -899,10 +915,11 @@ var Inbox = (function () {
// Send the message when enter pressend
$(inbox + 'inbox-new input').keyup(function(e) {
if(e.keyCode == 13) {
if(Common.exists(dHovered))
if(Common.exists(dHovered)) {
Search.addBuddy(destination, $(dHovered).attr('data-xid'));
else
} else {
self.checkMessage();
}
}
});
@ -948,7 +965,7 @@ var Inbox = (function () {
// File upload
var attach_options = {
dataType: 'xml',
dataType: 'xml',
beforeSubmit: self.waitAttach,
success: self.handleAttach
};

View file

@ -161,8 +161,9 @@ var IntegrateBox = (function () {
self.close();
// Media integration not wanted?
if(DataStore.getDB(Connection.desktop_hash, 'options', 'integratemedias') == '0')
if(DataStore.getDB(Connection.desktop_hash, 'options', 'integratemedias') == '0') {
return true;
}
// Apply the HTML code
var dom_code = self.code(service, url);

View file

@ -74,8 +74,9 @@ var Interface = (function () {
try {
// Item exists?
if(Common.exists('#general-wait'))
if(Common.exists('#general-wait')) {
return false;
}
// Generate the HTML code
var html =
@ -178,8 +179,9 @@ var Interface = (function () {
var more_content = '#page-switch .more-content';
// Yet displayed?
if(Common.exists(more_content))
if(Common.exists(more_content)) {
return Bubble.close();
}
// Add the bubble
Bubble.show(more_content);
@ -397,32 +399,48 @@ var Interface = (function () {
var date = DateUtils.getXMPPTime('local');
var type = $('#' + hash).attr('data-type');
var direction = $('html').attr('dir') || 'ltr';
var content_sel = $(content);
// Filter the content smileys
$(content).find('img.emoticon').each(function() {
content_sel.find('img.emoticon').each(function() {
$(this).replaceWith($(this).attr('alt'));
});
// Remove the useless attributes
$(content).removeAttr('data-type').removeAttr('data-stamp');
content_sel.removeAttr('data-type').removeAttr('data-stamp');
// Remove the content avatars
$(content).find('.avatar-container').remove();
content_sel.find('.avatar-container').remove();
// Remove the content info
content_sel.find('.correction-edit, .message-marker, .corrected-info, .correction-label').remove();
// Remove the content click events
$(content).find('a').removeAttr('onclick');
content_sel.find('a').removeAttr('onclick');
// Extract the content HTML code
content = $(content).parent().html();
content = content_sel.parent().html();
// No avatar?
if(!avatar || !avatar.match(/data:/))
if(!avatar || !avatar.match(/data:/)) {
avatar = 'none';
}
// POST the values to the server
$.post('./server/generate-chat.php', { 'content': content, 'xid': xid, 'nick': nick, 'avatar': avatar, 'date': date, 'type': type, 'direction': direction }, function(data) {
$.post('./server/generate-chat.php', {
'content': content,
'xid': xid,
'nick': nick,
'avatar': avatar,
'date': date,
'type': type,
'direction': direction
}, function(data) {
// Handled!
$(path + 'tooltip-waitlog').replaceWith('<a class="tooltip-actionlog" href="./server/download-chat.php?id=' + data + '" target="_blank">' + Common._e("Download file!") + '</a>');
$(path + 'tooltip-waitlog').replaceWith(
'<a class="tooltip-actionlog" href="./server/download-chat.php?id=' + data + '" target="_blank">' + Common._e("Download file!") + '</a>'
);
});
} catch(e) {
Console.error('Interface.generateChatLog', e);
@ -433,6 +451,31 @@ var Interface = (function () {
};
/**
* Returns whether chan has focus or not
* @public
* @param {string} hash
* @return {boolean}
*/
self.hasChanFocus = function(hash) {
var has_focus = true;
try {
if(!$('#page-switch .' + hash).hasClass('activechan') ||
!Common.isFocused() ||
(self.chat_focus_hash != hash)) {
has_focus = false;
}
} catch(e) {
Console.error('Interface.hasChanFocus', e);
} finally {
return has_focus;
}
};
/**
* Notifies the user from a new incoming message
* @public
@ -449,7 +492,7 @@ var Interface = (function () {
var active = $(tested).hasClass('activechan');
// We notify the user if he has not the focus on the chat
if(!active || !Common.isFocused() || (self.chat_focus_hash != hash)) {
if(self.hasChanFocus(hash) === false) {
if(!active) {
if(type == 'personal') {
$(tested + ', ' + chat_switch + 'more-button').addClass('chan-newmessage');
@ -509,10 +552,11 @@ var Interface = (function () {
try {
// Any pending events?
if(Common.exists('.one-counter[data-counter]'))
if(Common.exists('.one-counter[data-counter]')) {
self.title('new');
else
} else {
self.title('talk');
}
} catch(e) {
Console.error('Interface.updateTitle', e);
}
@ -534,8 +578,9 @@ var Interface = (function () {
$(chat_switch + hash).removeClass('chan-newmessage chan-unread');
// We reset the global notifications if no more unread messages
if(!$(chat_switch + 'chans .chan-newmessage').size())
if(!$(chat_switch + 'chans .chan-newmessage').size()) {
$(chat_switch + 'more-button').removeClass('chan-newmessage');
}
// We reset the chat counter
$('#' + hash).removeAttr('data-counter');
@ -598,8 +643,9 @@ var Interface = (function () {
// We show all the groups
$('#roster .one-group').show();
if(Search.search_filtered)
if(Search.search_filtered) {
Search.funnelFilterBuddy();
}
// Store this in the options
if((from == 'roster') && Options.loaded()) {
@ -687,6 +733,39 @@ var Interface = (function () {
$(document).ready(function() {
// Focus on the first visible input
$(window).focus(self.inputFocus);
// Re-focus to visible chat/groupchat input if typing when input blurred
$(document).keypress(function(evt) {
try {
// Don't trigger if not connected or popup opened
if(Common.isConnected() && !Common.exists('div.lock')) {
// Cannot work if an input/textarea is already focused or chat is not opened
var target_input_sel = $('.page-engine-chan .message-area:visible');
if(!target_input_sel.size() || $('input, textarea').is(':focus')) {
return;
}
// Get key value
var key_value = $.trim(String.fromCharCode(evt.which));
// Re-focus on opened chat?
if(key_value) {
// Get input values
value_input = target_input_sel.val();
// Append pressed key value
target_input_sel.val(value_input + key_value);
target_input_sel.focus();
// Put cursor at the end of input
target_input_sel[0].selectionStart = target_input_sel[0].selectionEnd = value_input.length + 1;
}
}
} catch(e) {
Console.error('Interface.launch[autofocus]', e);
}
});
});
} catch(e) {
Console.error('Interface.launch', e);

View file

@ -20,6 +20,352 @@ var IQ = (function () {
var self = {};
/**
* Handles OOB request
* @private
* @param {string} iqType
* @param {string} iqID
* @param {object} iqNode
* @return {undefined}
*/
self._handleOOBRequest = function(iqFrom, iqID, iqNode) {
try {
/* REF: http://xmpp.org/extensions/xep-0066.html */
OOB.handle(iqFrom, iqID, 'iq', iqNode);
Console.log('Received IQ OOB request: ' + iqFrom);
} catch(e) {
Console.error('IQ._handleOOBRequest', e);
}
};
/**
* Handles OOB reply
* @private
* @param {object} iqResponse
* @param {string} iqFrom
* @param {string} iqType
* @param {string} iqID
* @param {object} iqNode
* @return {undefined}
*/
self._handleOOBReply = function(iqResponse, iqFrom, iqType, iqID, iqNode) {
try {
// Get the values
var oob_url = DataStore.getDB(Connection.desktop_hash, 'send/url', iqID);
var oob_desc = DataStore.getDB(Connection.desktop_hash, 'send/desc', iqID);
var notif_id = hex_md5(oob_url + oob_desc + iqType + iqFrom + iqID);
if($(iqNode).find('error').size()) {
// Error?
if($(iqNode).find('error not-acceptable').size()) {
// Rejected?
Notification.create('send_reject', iqFrom, [iqFrom, oob_url, 'iq', iqID, iqNode], oob_desc, notif_id);
} else {
// Failed?
Notification.create('send_fail', iqFrom, [iqFrom, oob_url, 'iq', iqID, iqNode], oob_desc, notif_id);
}
// Remove the file
$.get(oob_url + '&action=remove');
} else if(iqType == 'result') {
// Success?
Notification.create('send_accept', iqFrom, [iqFrom, oob_url, 'iq', iqID, iqNode], oob_desc, notif_id);
}
} catch(e) {
Console.error('IQ._handleOOBReply', e);
}
};
/**
* Handles Software Version
* @private
* @param {object} iqResponse
* @param {string} iqFrom
* @return {undefined}
*/
self._handleSoftwareVersion = function(iqResponse, iqFrom) {
try {
/* REF: http://xmpp.org/extensions/xep-0092.html */
iqQuery = iqResponse.setQuery(NS_VERSION);
iqQuery.appendChild(iqResponse.buildNode('name', {'xmlns': NS_VERSION}, Caps.disco_infos.identity.name));
iqQuery.appendChild(iqResponse.buildNode('version', {'xmlns': NS_VERSION}, JAPPIX_VERSION));
iqQuery.appendChild(iqResponse.buildNode('os', {'xmlns': NS_VERSION}, BrowserDetect.OS));
con.send(iqResponse);
Console.log('Received software version query: ' + iqFrom);
} catch(e) {
Console.error('IQ._handleSoftwareVersion', e);
}
};
/**
* Handles Last Activity
* @private
* @param {object} iqResponse
* @param {string} iqFrom
* @return {undefined}
*/
self._handleLastActivity = function(iqResponse, iqFrom) {
try {
/* REF: http://xmpp.org/extensions/xep-0012.html */
iqQuery = iqResponse.setQuery(NS_LAST);
iqQuery.setAttribute('seconds', DateUtils.getLastActivity());
con.send(iqResponse);
Console.log('Received last activity query: ' + iqFrom);
} catch(e) {
Console.error('IQ._handleLastActivity', e);
}
};
/**
* Handles Privacy Lists
* @private
* @param {object} iqResponse
* @param {string} iqFrom
* @param {string} iqQuery
* @return {undefined}
*/
self._handlePrivacyLists = function(iqResponse, iqFrom, iqQuery) {
try {
// REF : http://xmpp.org/extensions/xep-0016.html
// Roster push
con.send(iqResponse);
// Get the lists
$(iqQuery).find('list').each(function() {
Privacy.get($(this).attr('name'));
});
Console.log('Received privacy lists push: ' + iqFrom);
} catch(e) {
Console.error('IQ._handlePrivacyLists', e);
}
};
/**
* Handles Roster Push
* @private
* @param {object} iqResponse
* @param {string} iqFrom
* @param {string} iqQuery
* @return {undefined}
*/
self._handleRosterPush = function(iqResponse, iqFrom, iqQuery) {
try {
// REF : http://xmpp.org/extensions/xep-0092.html
// Roster push
con.send(iqResponse);
// Get the values
$(iqQuery).find('item').each(function() {
Roster.parse($(this), 'presence');
});
Console.log('Received roster push: ' + iqFrom);
} catch(e) {
Console.error('IQ._handleRosterPush', e);
}
};
/**
* Handles Roster Item Exchange
* @private
* @param {object} iqNode
* @param {string} iqFrom
* @return {undefined}
*/
self._handleRosterItemExchange = function(iqNode, iqFrom) {
try {
// Open a new notification
Notification.create('rosterx', iqFrom, [iqNode], '');
Console.log('Roster Item Exchange from: ' + iqFrom);
} catch(e) {
Console.error('IQ._handleRosterItemExchange', e);
}
};
/**
* Handles Disco Info
* @private
* @param {object} iqResponse
* @param {string} iqFrom
* @return {undefined}
*/
self._handleDiscoInfo = function(iqResponse, iqFrom) {
try {
/* REF: http://xmpp.org/extensions/xep-0030.html */
iqQuery = iqResponse.setQuery(NS_DISCO_INFO);
// We set the name of the client
iqQuery.appendChild(iqResponse.buildNode('identity', {
'category': Caps.disco_infos.identity.category,
'type': Caps.disco_infos.identity.type,
'name': Caps.disco_infos.identity.name,
'xmlns': NS_DISCO_INFO
}));
// We set all the supported features
var disco_infos = Caps.myDiscoInfos();
$.each(disco_infos, function(i, disco_info) {
iqQuery.appendChild(iqResponse.buildNode('feature', {'var': disco_info, 'xmlns': NS_DISCO_INFO}));
});
con.send(iqResponse);
Console.log('Received disco#infos query: ' + iqFrom);
} catch(e) {
Console.error('IQ._handleDiscoInfo', e);
}
};
/**
* Handles User Time
* @private
* @param {object} iqResponse
* @param {string} iqFrom
* @return {undefined}
*/
self._handleUserTime = function(iqResponse, iqFrom) {
try {
/* REF: http://xmpp.org/extensions/xep-0202.html */
var iqTime = iqResponse.appendNode('time', {
'xmlns': NS_URN_TIME
});
iqTime.appendChild(iqResponse.buildNode('tzo', {
'xmlns': NS_URN_TIME
}, DateUtils.getTZO()));
iqTime.appendChild(iqResponse.buildNode('utc', {
'xmlns': NS_URN_TIME
}, DateUtils.getXMPPTime('utc')));
con.send(iqResponse);
Console.log('Received local time query: ' + iqFrom);
} catch(e) {
Console.error('IQ._handleUserTime', e);
}
};
/**
* Handles Ping
* @private
* @param {object} iqResponse
* @param {string} iqFrom
* @return {undefined}
*/
self._handlePing = function(iqResponse, iqFrom) {
try {
/* REF: http://xmpp.org/extensions/xep-0199.html */
con.send(iqResponse);
Console.log('Received a ping: ' + iqFrom);
} catch(e) {
Console.error('IQ._handlePing', e);
}
};
/**
* Handles Jingle
* @private
* @param {string} iqFrom
* @return {undefined}
*/
self._handleJingle = function(iqFrom) {
try {
/* REF: http://xmpp.org/extensions/xep-0166.html */
// Handled via JSJaCJingle.route() (see above)
Console.log('Received a Jingle packet: ' + iqFrom);
} catch(e) {
Console.error('IQ._handleJingle', e);
}
};
/**
* Raises a not implemented error
* @private
* @param {object} iqResponse
* @param {object} iqNode
* @param {string} iqFrom
* @return {undefined}
*/
self._raiseNotImplemented = function(iqResponse, iqNode, iqFrom) {
try {
// Change IQ type
iqResponse.setType('error');
// Append stanza content
for(var c = 0; c < iqNode.childNodes.length; c++) {
iqResponse.getNode().appendChild(iqNode.childNodes.item(c).cloneNode(true));
}
// Append error content
var iqError = iqResponse.appendNode('error', {'xmlns': NS_CLIENT, 'code': '501', 'type': 'cancel'});
iqError.appendChild(iqResponse.buildNode('feature-not-implemented', {'xmlns': NS_STANZAS}));
iqError.appendChild(iqResponse.buildNode('text', {'xmlns': NS_STANZAS}, Common._e("The feature requested is not implemented by the recipient or server and therefore cannot be processed.")));
con.send(iqResponse);
Console.log('Received an unsupported IQ query from: ' + iqFrom);
} catch(e) {
Console.error('IQ._raiseNotImplemented', e);
}
};
/**
* Handles an incoming IQ packet
* @public
@ -37,9 +383,6 @@ var IQ = (function () {
var iqQuery = iq.getQuery();
var iqType = iq.getType();
// Handle Jingle packet?
JSJaCJingle_route(iq);
// Build the response
var iqResponse = new JSJaCIQ();
@ -49,178 +392,62 @@ var IQ = (function () {
// OOB request
if((iqQueryXMLNS == NS_IQOOB) && (iqType == 'set')) {
/* REF: http://xmpp.org/extensions/xep-0066.html */
OOB.handle(iqFrom, iqID, 'iq', iqNode);
Console.log('Received IQ OOB request: ' + iqFrom);
self._handleOOBRequest(iqFrom, iqID, iqNode);
}
// OOB reply
else if(DataStore.getDB(Connection.desktop_hash, 'send/url', iqID)) {
// Get the values
var oob_url = DataStore.getDB(Connection.desktop_hash, 'send/url', iqID);
var oob_desc = DataStore.getDB(Connection.desktop_hash, 'send/desc', iqID);
var notif_id = hex_md5(oob_url + oob_desc + iqType + iqFrom + iqID);
if($(iqNode).find('error').size()) {
// Error?
if($(iqNode).find('error not-acceptable').size()) {
// Rejected?
Notification.create('send_reject', iqFrom, [iqFrom, oob_url, 'iq', iqID, iqNode], oob_desc, notif_id);
} else {
// Failed?
Notification.create('send_fail', iqFrom, [iqFrom, oob_url, 'iq', iqID, iqNode], oob_desc, notif_id);
}
// Remove the file
$.get(oob_url + '&action=remove');
} else if(iqType == 'result') {
// Success?
Notification.create('send_accept', iqFrom, [iqFrom, oob_url, 'iq', iqID, iqNode], oob_desc, notif_id);
}
self._handleOOBReply(iqResponse, iqFrom, iqType, iqID, iqNode);
}
// Software version query
else if((iqQueryXMLNS == NS_VERSION) && (iqType == 'get')) {
/* REF: http://xmpp.org/extensions/xep-0092.html */
iqQuery = iqResponse.setQuery(NS_VERSION);
iqQuery.appendChild(iqResponse.buildNode('name', {'xmlns': NS_VERSION}, 'Jappix'));
iqQuery.appendChild(iqResponse.buildNode('version', {'xmlns': NS_VERSION}, JAPPIX_VERSION));
iqQuery.appendChild(iqResponse.buildNode('os', {'xmlns': NS_VERSION}, BrowserDetect.OS));
con.send(iqResponse);
Console.log('Received software version query: ' + iqFrom);
self._handleSoftwareVersion(iqResponse, iqFrom);
}
// Last activity query
else if((iqQueryXMLNS == NS_LAST) && (iqType == 'get')) {
/* REF: http://xmpp.org/extensions/xep-0012.html */
iqQuery = iqResponse.setQuery(NS_LAST);
iqQuery.setAttribute('seconds', DateUtils.getLastActivity());
con.send(iqResponse);
Console.log('Received last activity query: ' + iqFrom);
self._handleLastActivity(iqResponse, iqFrom);
}
// Privacy lists push
else if((iqQueryXMLNS == NS_PRIVACY) && (iqType == 'set') && Common.isSafeStanza(iq)) {
// REF : http://xmpp.org/extensions/xep-0016.html
// Roster push
con.send(iqResponse);
// Get the lists
$(iqQuery).find('list').each(function() {
Privacy.get($(this).attr('name'));
});
Console.log('Received privacy lists push: ' + iqFrom);
self._handlePrivacyLists(iqResponse, iqFrom, iqQuery);
}
// Roster push
else if((iqQueryXMLNS == NS_ROSTER) && (iqType == 'set') && Common.isSafeStanza(iq)) {
// REF : http://xmpp.org/extensions/xep-0092.html
// Roster push
con.send(iqResponse);
// Get the values
$(iqQuery).find('item').each(function() {
Roster.parse($(this), 'presence');
});
Console.log('Received roster push: ' + iqFrom);
self._handleRosterPush(iqResponse, iqFrom, iqQuery);
}
// Roster Item Exchange query
else if($(iqNode).find('x[xmlns="' + NS_ROSTERX + '"]').size()) {
// Open a new notification
Notification.create('rosterx', iqFrom, [iqNode], '');
Console.log('Roster Item Exchange from: ' + iqFrom);
self._handleRosterItemExchange(iqNode, iqFrom);
}
// Disco info query
else if((iqQueryXMLNS == NS_DISCO_INFO) && (iqType == 'get')) {
/* REF: http://xmpp.org/extensions/xep-0030.html */
iqQuery = iqResponse.setQuery(NS_DISCO_INFO);
// We set the name of the client
iqQuery.appendChild(iqResponse.buildNode('identity', {
'category': 'client',
'type': 'web',
'name': 'Jappix',
'xmlns': NS_DISCO_INFO
}));
// We set all the supported features
var disco_infos = Caps.myDiscoInfos();
$.each(disco_infos, function(i, disco_info) {
iqQuery.appendChild(iqResponse.buildNode('feature', {'var': disco_info, 'xmlns': NS_DISCO_INFO}));
});
con.send(iqResponse);
Console.log('Received disco#infos query: ' + iqFrom);
self._handleDiscoInfo(iqResponse, iqFrom);
}
// User time query
else if($(iqNode).find('time').size() && (iqType == 'get')) {
/* REF: http://xmpp.org/extensions/xep-0202.html */
var iqTime = iqResponse.appendNode('time', {'xmlns': NS_URN_TIME});
iqTime.appendChild(iqResponse.buildNode('tzo', {'xmlns': NS_URN_TIME}, DateUtils.getTZO()));
iqTime.appendChild(iqResponse.buildNode('utc', {'xmlns': NS_URN_TIME}, DateUtils.getXMPPTime('utc')));
con.send(iqResponse);
Console.log('Received local time query: ' + iqFrom);
self._handleUserTime(iqResponse, iqFrom);
}
// Ping
else if($(iqNode).find('ping').size() && (iqType == 'get')) {
/* REF: http://xmpp.org/extensions/xep-0199.html */
con.send(iqResponse);
Console.log('Received a ping: ' + iqFrom);
self._handlePing(iqResponse, iqFrom);
}
// Jingle
else if($(iqNode).find('jingle').size()) {
/* REF: http://xmpp.org/extensions/xep-0166.html */
// Handled via JSJaCJingle_route() (see above)
Console.log('Received a Jingle packet: ' + iqFrom);
self._handleJingle(iqFrom);
}
// Not implemented
else if(!$(iqNode).find('error').size() && ((iqType == 'get') || (iqType == 'set'))) {
// Change IQ type
iqResponse.setType('error');
// Append stanza content
for(var c = 0; c < iqNode.childNodes.length; c++) {
iqResponse.getNode().appendChild(iqNode.childNodes.item(c).cloneNode(true));
}
// Append error content
var iqError = iqResponse.appendNode('error', {'xmlns': NS_CLIENT, 'code': '501', 'type': 'cancel'});
iqError.appendChild(iqResponse.buildNode('feature-not-implemented', {'xmlns': NS_STANZAS}));
iqError.appendChild(iqResponse.buildNode('text', {'xmlns': NS_STANZAS}, Common._e("The feature requested is not implemented by the recipient or server and therefore cannot be processed.")));
con.send(iqResponse);
Console.log('Received an unsupported IQ query from: ' + iqFrom);
self._raiseNotImplemented(iqResponse, iqNode, iqFrom);
}
} catch(e) {
Console.error('IQ.handle', e);

File diff suppressed because it is too large Load diff

View file

@ -1,138 +1,138 @@
/**
* jQuery.timers - Timer abstractions for jQuery
* Written by Blair Mitchelmore (blair DOT mitchelmore AT gmail DOT com)
* Licensed under the WTFPL (http://sam.zoy.org/wtfpl/).
* Date: 2009/10/16
*
* @author Blair Mitchelmore
* @version 1.2
*
**/
jQuery.fn.extend({
everyTime: function(interval, label, fn, times) {
return this.each(function() {
jQuery.timer.add(this, interval, label, fn, times);
});
},
oneTime: function(interval, label, fn) {
return this.each(function() {
jQuery.timer.add(this, interval, label, fn, 1);
});
},
stopTime: function(label, fn) {
return this.each(function() {
jQuery.timer.remove(this, label, fn);
});
}
});
jQuery.extend({
timer: {
global: [],
guid: 1,
dataKey: "jQuery.timer",
regex: /^([0-9]+(?:\.[0-9]*)?)\s*(.*s)?$/,
powers: {
// Yeah this is major overkill...
'ms': 1,
'cs': 10,
'ds': 100,
's': 1000,
'das': 10000,
'hs': 100000,
'ks': 1000000
},
timeParse: function(value) {
if (value == undefined || value == null)
return null;
var result = this.regex.exec(jQuery.trim(value.toString()));
if (result[2]) {
var num = parseFloat(result[1]);
var mult = this.powers[result[2]] || 1;
return num * mult;
} else {
return value;
}
},
add: function(element, interval, label, fn, times) {
var counter = 0;
if (jQuery.isFunction(label)) {
if (!times)
times = fn;
fn = label;
label = interval;
}
interval = jQuery.timer.timeParse(interval);
if (typeof interval != 'number' || isNaN(interval) || interval < 0)
return;
if (typeof times != 'number' || isNaN(times) || times < 0)
times = 0;
times = times || 0;
var timers = jQuery.data(element, this.dataKey) || jQuery.data(element, this.dataKey, {});
if (!timers[label])
timers[label] = {};
fn.timerID = fn.timerID || this.guid++;
var handler = function() {
if ((++counter > times && times !== 0) || fn.call(element, counter) === false)
jQuery.timer.remove(element, label, fn);
};
handler.timerID = fn.timerID;
if (!timers[label][fn.timerID])
timers[label][fn.timerID] = window.setInterval(handler,interval);
this.global.push( element );
},
remove: function(element, label, fn) {
var timers = jQuery.data(element, this.dataKey), ret;
if ( timers ) {
if (!label) {
for ( label in timers )
this.remove(element, label, fn);
} else if ( timers[label] ) {
if ( fn ) {
if ( fn.timerID ) {
window.clearInterval(timers[label][fn.timerID]);
delete timers[label][fn.timerID];
}
} else {
for ( var fn in timers[label] ) {
window.clearInterval(timers[label][fn]);
delete timers[label][fn];
}
}
for ( ret in timers[label] ) break;
if ( !ret ) {
ret = null;
delete timers[label];
}
}
for ( ret in timers ) break;
if ( !ret )
jQuery.removeData(element, this.dataKey);
}
}
}
});
jQuery(window).bind("unload", function() {
jQuery.each(jQuery.timer.global, function(index, item) {
jQuery.timer.remove(item);
});
});
/**
* jQuery.timers - Timer abstractions for jQuery
* Written by Blair Mitchelmore (blair DOT mitchelmore AT gmail DOT com)
* Licensed under the WTFPL (http://sam.zoy.org/wtfpl/).
* Date: 2009/10/16
*
* @author Blair Mitchelmore
* @version 1.2
*
**/
jQuery.fn.extend({
everyTime: function(interval, label, fn, times) {
return this.each(function() {
jQuery.timer.add(this, interval, label, fn, times);
});
},
oneTime: function(interval, label, fn) {
return this.each(function() {
jQuery.timer.add(this, interval, label, fn, 1);
});
},
stopTime: function(label, fn) {
return this.each(function() {
jQuery.timer.remove(this, label, fn);
});
}
});
jQuery.extend({
timer: {
global: [],
guid: 1,
dataKey: "jQuery.timer",
regex: /^([0-9]+(?:\.[0-9]*)?)\s*(.*s)?$/,
powers: {
// Yeah this is major overkill...
'ms': 1,
'cs': 10,
'ds': 100,
's': 1000,
'das': 10000,
'hs': 100000,
'ks': 1000000
},
timeParse: function(value) {
if (value == undefined || value == null)
return null;
var result = this.regex.exec(jQuery.trim(value.toString()));
if (result[2]) {
var num = parseFloat(result[1]);
var mult = this.powers[result[2]] || 1;
return num * mult;
} else {
return value;
}
},
add: function(element, interval, label, fn, times) {
var counter = 0;
if (jQuery.isFunction(label)) {
if (!times)
times = fn;
fn = label;
label = interval;
}
interval = jQuery.timer.timeParse(interval);
if (typeof interval != 'number' || isNaN(interval) || interval < 0)
return;
if (typeof times != 'number' || isNaN(times) || times < 0)
times = 0;
times = times || 0;
var timers = jQuery.data(element, this.dataKey) || jQuery.data(element, this.dataKey, {});
if (!timers[label])
timers[label] = {};
fn.timerID = fn.timerID || this.guid++;
var handler = function() {
if ((++counter > times && times !== 0) || fn.call(element, counter) === false)
jQuery.timer.remove(element, label, fn);
};
handler.timerID = fn.timerID;
if (!timers[label][fn.timerID])
timers[label][fn.timerID] = window.setInterval(handler,interval);
this.global.push( element );
},
remove: function(element, label, fn) {
var timers = jQuery.data(element, this.dataKey), ret;
if ( timers ) {
if (!label) {
for ( label in timers )
this.remove(element, label, fn);
} else if ( timers[label] ) {
if ( fn ) {
if ( fn.timerID ) {
window.clearInterval(timers[label][fn.timerID]);
delete timers[label][fn.timerID];
}
} else {
for ( var fn in timers[label] ) {
window.clearInterval(timers[label][fn]);
delete timers[label][fn];
}
}
for ( ret in timers[label] ) break;
if ( !ret ) {
ret = null;
delete timers[label];
}
}
for ( ret in timers ) break;
if ( !ret )
jQuery.removeData(element, this.dataKey);
}
}
}
});
jQuery(window).bind("unload", function() {
jQuery.each(jQuery.timer.global, function(index, item) {
jQuery.timer.remove(item);
});
});

File diff suppressed because it is too large Load diff

View file

@ -14,11 +14,11 @@ Authors: Stefan Strigler, Valérian Saliou, Zash, Maranda
* @fileoverview Magic dependency loading. Taken from script.aculo.us
* and modified to break it.
* @author Stefan Strigler steve@zeank.in-berlin.de
* @version $Revision$
* @version 1.3
*/
var JSJaC = {
Version: '$Rev$',
Version: '1.3',
bind: function(fn, obj, optArg) {
return function(arg) {
return fn.apply(obj, [arg, optArg]);
@ -26,9 +26,6 @@ var JSJaC = {
}
};
if (typeof JSJaCConnection == 'undefined')
JSJaC.load();
/* Copyright 2006 Erik Arvidsson
@ -52,7 +49,7 @@ if (typeof JSJaCConnection == 'undefined')
* this code is taken from
* http://webfx.eae.net/dhtml/xmlextras/xmlextras.html
* @author Stefan Strigler steve@zeank.in-berlin.de
* @version $Revision$
* @version 1.3
*/
/**
@ -282,7 +279,7 @@ if (window.XMLSerializer &&
/**
* @fileoverview Collection of functions to make live easier
* @author Stefan Strigler
* @version $Revision$
* @version 1.3
*/
/**
@ -1381,7 +1378,7 @@ JSJaCJSON.parse = function (str) {
* @fileoverview This file contains all things that make life easier when
* dealing with JIDs
* @author Stefan Strigler
* @version $Revision$
* @version 1.3
*/
/**
@ -1714,7 +1711,7 @@ var JSJaCBuilder = {
/**
* @fileoverview Contains all Jabber/XMPP packet related classes.
* @author Stefan Strigler steve@zeank.in-berlin.de
* @version $Revision$
* @version 1.3
*/
var JSJACPACKET_USE_XMLNS = true;
@ -2567,7 +2564,7 @@ function JSJaCKeys(func,oDbg) {
* @fileoverview Contains all things in common for all subtypes of connections
* supported.
* @author Stefan Strigler steve@zeank.in-berlin.de
* @version $Revision$
* @version 1.3
*/
/**
@ -3601,10 +3598,6 @@ JSJaCConnection.prototype._handlePID = function(packet) {
if (!packet.getID())
return false;
if (packet.pType() != 'iq' ||
(packet.getType() != 'error' && packet.getType() != 'result'))
return false;
var jid = packet.getFrom() || this.jid;
if (packet.getFrom() == this.domain)
@ -3723,7 +3716,7 @@ JSJaCConnection.prototype._parseStreamFeatures = function(doc) {
// Get legacy session capability if available
this.legacy_sessions=null;
if (doc.getElementsByTagName("session")[0]) {
if (doc.getElementsByTagName("session")) {
this.legacy_sessions=true;
}
@ -3955,7 +3948,7 @@ JSJaCConnection.prototype._setStatus = function(status) {
/**
* @fileoverview All stuff related to HTTP Binding
* @author Stefan Strigler steve@zeank.in-berlin.de
* @version $Revision$
* @version 1.3
*/
/**
@ -4865,7 +4858,26 @@ JSJaCWebSocketConnection.prototype._parseXml = function(s) {
this.oDbg.log('Parsing: ' + s, 4);
try {
doc = XmlDocument.create('stream', NS_STREAM);
if(s.indexOf('<stream:stream') === -1) {
if(s.trim() == '</stream:stream>') {
// Consider session as closed
this.oDbg.log("session terminated", 1);
clearTimeout(this._timeout); // remove timer
clearInterval(this._interval);
clearInterval(this._inQto);
try {
DataStore.removeDB(MINI_HASH, 'jsjac', 'state');
} catch (e) {}
this._connected = false;
this._handleEvent('onerror',JSJaCError('503','cancel','session-terminate'));
this.oDbg.log("Disconnected.",1);
this._handleEvent('ondisconnect');
return null;
} else if(s.indexOf('<stream:stream') === -1) {
// Wrap every stanza into stream element, so that XML namespaces work properly.
doc.loadXML("<stream:stream xmlns:stream='" + NS_STREAM + "' xmlns='jabber:client'>" + s + "</stream:stream>");
return doc.documentElement.firstChild;
@ -5018,3 +5030,61 @@ JSJaCWebSocketConnection.prototype._sendRaw = function(xml, cb, arg) {
return true;
};
/*exported JSJaCUtils */
/**
* Various utilities put together so that they don't pollute global
* name space.
* @namespace
*/
var JSJaCUtils = {
/**
* XOR two strings of equal length.
* @param {string} s1 first string to XOR.
* @param {string} s2 second string to XOR.
* @return {string} s1 ^ s2.
*/
xor: function(s1, s2) {
/*jshint bitwise: false */
if(!s1) {
return s2;
}
if(!s2) {
return s1;
}
var result = '';
for(var i = 0; i < s1.length; i++) {
result += String.fromCharCode(s1.charCodeAt(i) ^ s2.charCodeAt(i));
}
return result;
},
/**
* Create nonce value of given size.
* @param {int} size size of the nonce that should be generated.
* @return {string} generated nonce.
*/
cnonce: function(size) {
var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var cnonce = '';
for (var i = 0; i < size; i++) {
cnonce += tab.charAt(Math.round(Math.random(new Date().getTime()) * (tab.length - 1)));
}
return cnonce;
},
/**
* Current timestamp.
* @return Seconds since 1.1.1970.
* @type int
*/
now: function() {
if (Date.now && typeof Date.now == 'function') {
return Date.now();
} else {
return new Date().getTime();
}
}
};

View file

@ -1,116 +1,116 @@
// jXHR.js (JSON-P XHR)
// v0.1 (c) Kyle Simpson
// License: MIT
// modified by gueron Jonathan to work with strophe lib
// for http://www.iadvize.com
(function(global){
var SETTIMEOUT = global.setTimeout, // for better compression
doc = global.document,
callback_counter = 0;
global.jXHR = function() {
var script_url,
script_loaded,
jsonp_callback,
scriptElem,
publicAPI = null;
function removeScript() { try { scriptElem.parentNode.removeChild(scriptElem); } catch (err) { } }
function reset() {
script_loaded = false;
script_url = "";
removeScript();
scriptElem = null;
fireReadyStateChange(0);
}
function ThrowError(msg) {
try {
publicAPI.onerror.call(publicAPI,msg,script_url);
} catch (err) {
//throw new Error(msg);
}
}
function handleScriptLoad() {
if ((this.readyState && this.readyState!=="complete" && this.readyState!=="loaded") || script_loaded) { return; }
this.onload = this.onreadystatechange = null; // prevent memory leak
script_loaded = true;
if (publicAPI.readyState !== 4) ThrowError("handleScriptLoad: Script failed to load ["+script_url+"].");
removeScript();
}
function parseXMLString(xmlStr) {
var xmlDoc = null;
if(window.DOMParser) {
var parser = new DOMParser();
xmlDoc = parser.parseFromString(xmlStr,"text/xml");
}
else {
xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async="false";
xmlDoc.loadXML(xmlStr);
}
return xmlDoc;
}
function fireReadyStateChange(rs,args) {
args = args || [];
publicAPI.readyState = rs;
if (rs == 4) {
publicAPI.responseText = args[0].reply;
publicAPI.responseXML = parseXMLString(args[0].reply);
}
if (typeof publicAPI.onreadystatechange === "function") publicAPI.onreadystatechange.apply(publicAPI,args);
}
publicAPI = {
onerror:null,
onreadystatechange:null,
readyState:0,
status:200,
responseBody: null,
responseText: null,
responseXML: null,
open:function(method,url){
reset();
var internal_callback = "cb"+(callback_counter++);
(function(icb){
global.jXHR[icb] = function() {
try { fireReadyStateChange.call(publicAPI,4,arguments); }
catch(err) {
publicAPI.readyState = -1;
ThrowError("Script failed to run ["+script_url+"].");
}
global.jXHR[icb] = null;
};
})(internal_callback);
script_url = url + '?callback=?jXHR&data=';
script_url = script_url.replace(/=\?jXHR/,"=jXHR."+internal_callback);
fireReadyStateChange(1);
},
send:function(data){
script_url = script_url + encodeURIComponent(data);
SETTIMEOUT(function(){
scriptElem = doc.createElement("script");
scriptElem.setAttribute("type","text/javascript");
scriptElem.onload = scriptElem.onreadystatechange = function(){handleScriptLoad.call(scriptElem);};
scriptElem.setAttribute("src",script_url);
doc.getElementsByTagName("head")[0].appendChild(scriptElem);
},0);
fireReadyStateChange(2);
},
abort:function(){},
setRequestHeader:function(){}, // noop
getResponseHeader:function(){return "";}, // basically noop
getAllResponseHeaders:function(){return [];} // ditto
};
reset();
return publicAPI;
};
})(window);
// jXHR.js (JSON-P XHR)
// v0.1 (c) Kyle Simpson
// License: MIT
// modified by gueron Jonathan to work with strophe lib
// for http://www.iadvize.com
(function(global){
var SETTIMEOUT = global.setTimeout, // for better compression
doc = global.document,
callback_counter = 0;
global.jXHR = function() {
var script_url,
script_loaded,
jsonp_callback,
scriptElem,
publicAPI = null;
function removeScript() { try { scriptElem.parentNode.removeChild(scriptElem); } catch (err) { } }
function reset() {
script_loaded = false;
script_url = "";
removeScript();
scriptElem = null;
fireReadyStateChange(0);
}
function ThrowError(msg) {
try {
publicAPI.onerror.call(publicAPI,msg,script_url);
} catch (err) {
//throw new Error(msg);
}
}
function handleScriptLoad() {
if ((this.readyState && this.readyState!=="complete" && this.readyState!=="loaded") || script_loaded) { return; }
this.onload = this.onreadystatechange = null; // prevent memory leak
script_loaded = true;
if (publicAPI.readyState !== 4) ThrowError("handleScriptLoad: Script failed to load ["+script_url+"].");
removeScript();
}
function parseXMLString(xmlStr) {
var xmlDoc = null;
if(window.DOMParser) {
var parser = new DOMParser();
xmlDoc = parser.parseFromString(xmlStr,"text/xml");
}
else {
xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async="false";
xmlDoc.loadXML(xmlStr);
}
return xmlDoc;
}
function fireReadyStateChange(rs,args) {
args = args || [];
publicAPI.readyState = rs;
if (rs == 4) {
publicAPI.responseText = args[0].reply;
publicAPI.responseXML = parseXMLString(args[0].reply);
}
if (typeof publicAPI.onreadystatechange === "function") publicAPI.onreadystatechange.apply(publicAPI,args);
}
publicAPI = {
onerror:null,
onreadystatechange:null,
readyState:0,
status:200,
responseBody: null,
responseText: null,
responseXML: null,
open:function(method,url){
reset();
var internal_callback = "cb"+(callback_counter++);
(function(icb){
global.jXHR[icb] = function() {
try { fireReadyStateChange.call(publicAPI,4,arguments); }
catch(err) {
publicAPI.readyState = -1;
ThrowError("Script failed to run ["+script_url+"].");
}
global.jXHR[icb] = null;
};
})(internal_callback);
script_url = url + '?callback=?jXHR&data=';
script_url = script_url.replace(/=\?jXHR/,"=jXHR."+internal_callback);
fireReadyStateChange(1);
},
send:function(data){
script_url = script_url + encodeURIComponent(data);
SETTIMEOUT(function(){
scriptElem = doc.createElement("script");
scriptElem.setAttribute("type","text/javascript");
scriptElem.onload = scriptElem.onreadystatechange = function(){handleScriptLoad.call(scriptElem);};
scriptElem.setAttribute("src",script_url);
doc.getElementsByTagName("head")[0].appendChild(scriptElem);
},0);
fireReadyStateChange(2);
},
abort:function(){},
setRequestHeader:function(){}, // noop
getResponseHeader:function(){return "";}, // basically noop
getAllResponseHeaders:function(){return [];} // ditto
};
reset();
return publicAPI;
};
})(window);

View file

@ -34,22 +34,30 @@ var Links = (function () {
var target;
// Links style
if(!style)
if(!style) {
style = '';
else
} else {
style = ' style="' + style + '"';
}
// Open in new tabs
if(mode != 'xhtml-im')
if(mode != 'xhtml-im') {
target = ' target="_blank"';
else
} else {
target = '';
}
// XMPP address
string = string.replace(/(\s|<br \/>|^)(([a-zA-Z0-9\._-]+)@([a-zA-Z0-9\.\/_-]+))(,|\s|$)/gi, '$1<a href="xmpp:$2" target="_blank"' + style + '>$2</a>$5');
string = string.replace(
/(\s|<br \/>|^)(([a-zA-Z0-9\._-]+)@([a-zA-Z0-9\.\/_-]+))(,|\s|$)/gi,
'$1<a href="xmpp:$2" target="_blank"' + style + '>$2</a>$5'
);
// Simple link
string = string.replace(/(\s|<br \/>|^|\()((https?|ftp|file|xmpp|irc|mailto|vnc|webcal|ssh|ldap|smb|magnet|spotify)(:)([^<>'"\s\)]+))/gim, '$1<a href="$2"' + target + style + '>$2</a>');
string = string.replace(
/(\s|<br \/>|^|\()((https?|ftp|file|xmpp|irc|mailto|vnc|webcal|ssh|ldap|smb|magnet|spotify)(:)([^<>'"\s\)]+))/gim,
'$1<a href="$2"' + target + style + '>$2</a>'
);
return string;
} catch(e) {

View file

@ -35,6 +35,7 @@ var MAM = (function () {
self.map_reqs = {};
self.map_pending = {};
self.map_states = {};
self.map_messages = {};
self.msg_queue = {};
@ -311,11 +312,16 @@ var MAM = (function () {
if(c_message[0]) {
// Re-build a proper JSJaC message stanza
var message = JSJaCPacket.wrapNode(c_message[0]);
var message_node = message.getNode();
// Check message type
var type = message.getType() || 'chat';
if(type == 'chat') {
// Display function
var c_display_fn;
var c_display_msg_bool = false;
// Read message data
var xid = Common.bareXID(Common.getStanzaFrom(message));
var id = message.getID();
@ -331,50 +337,100 @@ var MAM = (function () {
var hash = hex_md5(xid);
var body = message.getBody();
// Read delay (required since we deal w/ a past message!)
var time, stamp;
var delay = c_delay.attr('stamp');
// Content message?
if(body) {
// Read delay (required since we deal w/ a past message!)
var time, stamp;
var delay = c_delay.attr('stamp');
if(delay) {
time = DateUtils.relative(delay);
stamp = DateUtils.extractStamp(Date.jab2date(delay));
}
// Last-minute checks before display
if(time && stamp && body) {
var mam_chunk_path = '#' + hash + ' .mam-chunk';
// No chat auto-scroll?
var no_scroll = Common.exists(mam_chunk_path);
// Select the custom target
var c_target_sel = function() {
return $(mam_chunk_path).filter(function() {
return $(this).attr('data-start') <= stamp && $(this).attr('data-end') >= stamp;
}).filter(':first');
};
// Display the message in that target
var c_msg_display = function() {
Message.display(type, from_xid, hash, b_name.htmlEnc(), body, time, stamp, 'old-message', true, null, mode, null, c_target_sel(), no_scroll);
};
// Hack: do not display the message in case we would duplicate it w/ current session messages
// only used when initiating a new chat, avoids collisions
if(!(xid in self.map_states) && $('#' + hash).find('.one-line.user-message:last').text() == body) {
return;
if(delay) {
time = DateUtils.relative(delay);
stamp = DateUtils.extractStamp(Date.jab2date(delay));
}
// Last-minute checks before display
if(time && stamp) {
var mam_chunk_path = '#' + hash + ' .mam-chunk';
// Markable message?
var is_markable = Markers.hasRequestMarker(message_node);
// No chat auto-scroll?
var no_scroll = Common.exists(mam_chunk_path);
// Select the custom target
var c_target_sel = function() {
return $(mam_chunk_path).filter(function() {
return $(this).attr('data-start') <= stamp && $(this).attr('data-end') >= stamp;
}).filter(':first');
};
if(c_target_sel().size()) {
// Display the message in that target
c_msg_display();
c_display_fn = function() {
// Display message
Message.display(
type,
from_xid,
hash,
b_name.htmlEnc(),
body,
time,
stamp,
'old-message',
true,
null,
mode,
id + '-mam',
c_target_sel(),
no_scroll,
undefined,
undefined,
undefined,
is_markable
);
self.map_messages[id] = 1;
};
c_display_msg_bool = c_target_sel().size() ? true : false;
// Hack: do not display the message in case we would duplicate it w/ current session messages
// only used when initiating a new chat, avoids collisions
if(!(xid in self.map_states) && $('#' + hash).find('.one-line.user-message:last').text() == body) {
return;
}
}
} else if(Markers.hasResponseMarker(message_node)) {
// Marked message? (by other party)
if(mode == 'him') {
var marked_message_id = Markers.getMessageID(message_node);
c_display_fn = function() {
var is_mam_marker = true;
Markers.handle(
from_xid,
message_node,
is_mam_marker
);
};
c_display_msg_bool = (self.map_messages[marked_message_id] === 1) ? true : false;
}
}
// Display message?
if(typeof c_display_fn == 'function') {
if(c_display_msg_bool === true) {
// Display message now
c_display_fn();
} else {
// Delay display (we may not have received the MAM reply ATM)
if(typeof self.msg_queue[xid] != 'object') {
self.msg_queue[xid] = [];
}
self.msg_queue[xid].push(c_msg_display);
self.msg_queue[xid].push(c_display_fn);
}
}
}

View file

@ -0,0 +1,428 @@
/*
Jappix - An open social platform
Implementation of XEP-0333: Chat Markers
-------------------------------------------------
License: AGPL
Author: Valérian Saliou
*/
// Bundle
var Markers = (function () {
/**
* Alias of this
* @private
*/
var self = {};
/* Constants */
self.MARK_TYPE_MARKABLE = 'markable';
self.MARK_TYPE_RECEIVED = 'received';
self.MARK_TYPE_DISPLAYED = 'displayed';
self.MARK_TYPE_ACKNOWLEDGED = 'acknowledged';
self.MARK_TYPES = {};
self.MARK_TYPES[self.MARK_TYPE_MARKABLE] = 1;
self.MARK_TYPES[self.MARK_TYPE_RECEIVED] = 1;
self.MARK_TYPES[self.MARK_TYPE_DISPLAYED] = 1;
self.MARK_TYPES[self.MARK_TYPE_ACKNOWLEDGED] = 1;
/**
* Returns whether entity supports message markers
* @public
* @param {string} xid
* @return {boolean}
*/
self.hasSupport = function(xid) {
var has_support = false;
try {
has_support = true ? $('#' + hex_md5(xid)).attr('data-markers') == 'true' : false;
} catch(e) {
Console.error('Markers.hasSupport', e);
} finally {
return has_support;
}
};
/**
* Returns whether request message is marked or not
* @public
* @param {object} message
* @return {boolean}
*/
self.hasRequestMarker = function(message) {
var has_request_marker = false;
try {
has_request_marker = ($(message).find('markable[xmlns="' + NS_URN_MARKERS + '"]').size() ? true : false);
} catch(e) {
Console.error('Markers.hasRequestMarker', e);
} finally {
return has_request_marker;
}
};
/**
* Returns whether response message is marked or not
* @public
* @param {object} message
* @return {boolean}
*/
self.hasResponseMarker = function(message) {
var has_response_marker = false;
try {
var marker_sel = $(message).find('[xmlns="' + NS_URN_MARKERS + '"]');
if(marker_sel.size()) {
var mark_type = marker_sel.prop('tagName').toLowerCase();
switch(mark_type) {
case self.MARK_TYPE_RECEIVED:
case self.MARK_TYPE_DISPLAYED:
case self.MARK_TYPE_ACKNOWLEDGED:
has_response_marker = true;
break;
}
}
} catch(e) {
Console.error('Markers.hasResponseMarker', e);
} finally {
return has_response_marker;
}
};
/**
* Returns the marked message ID
* @public
* @param {object} message
* @return {boolean}
*/
self.getMessageID = function(message) {
var message_id = null;
try {
message_id = $(message).find('[xmlns="' + NS_URN_MARKERS + '"]').attr('id');
} catch(e) {
Console.error('Markers.getMessageID', e);
} finally {
return message_id;
}
};
/**
* Marks a message
* @public
* @param {object} message
* @return {undefined}
*/
self.mark = function(message) {
try {
message.appendNode('markable', {
'xmlns': NS_URN_MARKERS
});
} catch(e) {
Console.error('Markers.mark', e);
}
};
/**
* Changes received message status (once received or read)
* @public
* @param {string} mark_type
* @param {object} message_id
* @return {undefined}
*/
self.change = function(to, mark_type, message_id, message_sel) {
try {
if(!(mark_type in self.MARK_TYPES)) {
throw 'Marker type (' + mark_type + ') not supported, aborting.';
}
// Store mark state
message_sel.attr('data-mark', mark_type);
var message = new JSJaCMessage();
message.setType('chat');
message.setTo(to);
message.appendNode(mark_type, {
'xmlns': NS_URN_MARKERS,
'id': message_id
});
con.send(message);
Console.debug('Markers.change', 'Changed marker to: ' + mark_type + ' for message with ID: ' + message_id + ' from: ' + to);
} catch(e) {
Console.error('Markers.change', e);
}
};
/**
* Handles marker change coming from Carbons
* @public
* @param {string} message
* @return {undefined}
*/
self.handleCarbonChange = function(message) {
try {
// Check the marker element is existing
var marker_sel = $(message).find('[xmlns="' + NS_URN_MARKERS + '"]');
if(marker_sel.size()) {
var xid = Common.bareXID(message.getTo());
var mark_type = marker_sel.prop('tagName').toLowerCase();
var mark_handle = false;
// Filter allowed markers
switch(mark_type) {
case self.MARK_TYPE_RECEIVED:
case self.MARK_TYPE_DISPLAYED:
case self.MARK_TYPE_ACKNOWLEDGED:
mark_handle = true;
break;
}
if(mark_handle === true) {
var mark_message_id = marker_sel.attr('id');
var message_sel = $('#' + hex_md5(xid) + ' .content .one-line[data-mode="him"][data-markable="true"]').filter(function() {
return ($(this).attr('data-id') + '') === (mark_message_id + '');
}).filter(':last');
if(!message_sel.size()) {
Console.warn('Markers.handleCarbonChange', 'Unknown message marker to keep in sync with Carbons for: ' + xid);
return false;
}
// Store mark state
message_sel.attr('data-mark', mark_type);
Console.debug('Markers.handleCarbonChange', 'Received Carbons chat marker (' + mark_type + ') from another resource for: ' + from);
}
}
} catch(e) {
Console.error('Markers.handleCarbonChange', e);
}
};
/**
* Handles a marked message
* @public
* @param {string} from
* @param {object} message
* @param {boolean} is_mam_marker
* @return {undefined}
*/
self.handle = function(from, message, is_mam_marker) {
try {
var xid = Common.bareXID(from);
var marker_sel = $(message).find('[xmlns="' + NS_URN_MARKERS + '"]');
if(marker_sel.size()) {
var mark_type = marker_sel.prop('tagName').toLowerCase();
var mark_message_id = marker_sel.attr('id');
if(is_mam_marker === true) {
mark_message_id += '-mam';
}
// Filter allowed markers
var mark_valid = false;
switch(mark_type) {
case self.MARK_TYPE_RECEIVED:
case self.MARK_TYPE_DISPLAYED:
case self.MARK_TYPE_ACKNOWLEDGED:
mark_valid = true;
break;
}
if(mark_valid === false) {
Console.warn('Markers.handle', 'Dropping unexpected chat marker (' + mark_type + ') from: ' + from);
return false;
}
// Find marked message target
var message_sel = $('#' + hex_md5(xid) + ' .content .one-line[data-mode="me"]').filter(function() {
return ($(this).attr('data-id') + '') === (mark_message_id + '');
}).filter(':last');
if(!message_sel.size()) {
Console.warn('Markers.handle', 'Dropping chat marker (' + mark_type + ') for inexisting message ID (' + mark_message_id + ') from: ' + from);
return false;
}
Console.debug('Markers.handle', 'Received chat marker (' + mark_type + ') from: ' + from);
// Finally display received marker
self._display(xid, message_sel, mark_type);
return true;
}
return false;
} catch(e) {
Console.error('Markers.handle', e);
return false;
}
};
/**
* Adds the markers input events
* @public
* @param {object} target
* @param {string} xid
* @param {string} hash
* @param {string} type
* @return {undefined}
*/
self.events = function(target, xid, hash, type) {
try {
target.focus(function() {
// Not needed
if(target.is(':disabled')) {
return;
}
// Send displayed message marker?
if(type == 'chat' && self.hasSupport(xid) === true) {
var last_message = $('#' + hash + ' .content .one-line.user-message[data-markable="true"]:last');
if(last_message.attr('data-mark') != self.MARK_TYPE_DISPLAYED) {
var last_message_id = last_message.attr('data-id');
var full_xid = Presence.highestPriority(xid) || xid;
if(last_message_id) {
self.change(
full_xid,
self.MARK_TYPE_DISPLAYED,
last_message_id,
last_message
);
}
}
}
});
} catch(e) {
Console.error('Markers.events', e);
}
};
/**
* Displays a marker
* @private
* @param {string} xid
* @param {object} message_sel
* @param {string} mark_type
* @return {boolean}
*/
self._display = function(xid, message_sel, mark_type) {
try {
// Get marker state translation
var marker_sel = message_sel.find('.message-marker');
var mark_message = null;
var css_classes = 'talk-images message-marker-read';
var marker_category = null;
switch(mark_type) {
case self.MARK_TYPE_RECEIVED:
marker_category = 'delivered';
marker_sel.removeClass(css_classes);
marker_sel.text(
Common._e("Delivered")
);
break;
case self.MARK_TYPE_DISPLAYED:
case self.MARK_TYPE_ACKNOWLEDGED:
marker_category = 'read';
marker_sel.addClass(css_classes);
marker_sel.text(
Common._e("Read")
);
break;
default:
return false;
}
if(marker_category !== null) {
marker_sel.attr('data-category', marker_category);
}
// Reset sending state
message_sel.removeClass('is-sending');
// Toggle marker visibility
message_sel.parents('.content').find('.one-line .message-marker').filter(function() {
var data_category = $(this).attr('data-category');
if(data_category != 'delivered' && data_category != 'read') {
return false;
}
// Leave older "read" checkpoint on screen
if(marker_category == 'delivered') {
return data_category == marker_category;
}
return true;
}).hide();
marker_sel.show();
return true;
} catch(e) {
Console.error('Markers._display', e);
return false;
}
};
/**
* Return class scope
*/
return self;
})();

View file

@ -93,12 +93,14 @@ var Me = (function () {
self.instance = function() {
try {
var me_sel = $('#me');
// Click events
$('#me .content a.go').click(function() {
me_sel.find('.content a.go').click(function() {
self.close();
});
$('#me .bottom .finish').click(self.close);
me_sel.find('.bottom .finish').click(self.close);
} catch(e) {
Console.error('Me.instance', e);
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -748,7 +748,7 @@ var JappixMini = (function () {
var resources_obj = {};
// Is this a groupchat?
if(JappixCommon.exists('#jappix_mini div.jm_conversation[data-type="groupchat"][data-xid="' + JappixCommon.encodeQuotes(xid) + '"]')) {
if(JappixCommon.exists('#jappix_mini div.jm_conversation[data-type="groupchat"][data-xid="' + JappixCommon.escapeQuotes(xid) + '"]')) {
xid = from;
}
@ -1003,7 +1003,7 @@ var JappixMini = (function () {
is_groupchat = true;
// Groupchat buddy presence (not me)
if(resource != unescape(jQuery(groupchat_path).attr('data-nick'))) {
if(resource != JappixCommon.unescapeQuotes(jQuery(groupchat_path).attr('data-nick'))) {
// Regenerate some stuffs
var groupchat = xid;
var groupchat_hash = hash;
@ -1059,7 +1059,7 @@ var JappixMini = (function () {
// Check against search string
var search = jQuery('#jappix_mini div.jm_roster div.jm_search input.jm_searchbox').val();
var regex = new RegExp('((^)|( ))' + JappixCommon.escapeRegex(search), 'gi');
var nick = unescape(jQuery(friend).data('nick'));
var nick = JappixCommon.unescapeQuotes(jQuery(friend).data('nick'));
if(search && !nick.match(regex)) {
jQuery(friend).hide();
@ -1110,7 +1110,7 @@ var JappixMini = (function () {
// Is it a valid server presence?
var valid = false;
if(!resource || (resource == unescape(jQuery('#jappix_mini #chat-' + hash + '[data-type="groupchat"]').attr('data-nick')))) {
if(!resource || (resource == JappixCommon.unescapeQuotes(jQuery('#jappix_mini #chat-' + hash + '[data-type="groupchat"]').attr('data-nick')))) {
valid = true;
}
@ -1154,7 +1154,7 @@ var JappixMini = (function () {
self.presence('', '', '', '', room + '/' + nickname, '', true, self.handleMUC);
// Update the nickname marker
jQuery('#jappix_mini #chat-' + hash).attr('data-nick', escape(nickname));
jQuery('#jappix_mini #chat-' + hash).attr('data-nick', JappixCommon.escapeQuotes(nickname));
}
// Handle normal presence
@ -1258,7 +1258,7 @@ var JappixMini = (function () {
// If the roster does not give us any nick the user may have send us a nickname to use with his first message
// @see http://xmpp.org/extensions/xep-0172.html
var known_roster_entry = jQuery('#jappix_mini a.jm_friend[data-xid="' + xid + '"]');
var known_roster_entry = jQuery('#jappix_mini a.jm_friend[data-xid="' + JappixCommon.escapeQuotes(xid) + '"]');
if(known_roster_entry.size() === 0) {
var subscription = known_roster_entry.attr('data-sub');
@ -1952,7 +1952,7 @@ var JappixMini = (function () {
jQuery('#jappix_mini div.jm_conversation[data-type="groupchat"]').each(function() {
var this_sub_sel = jQuery(this);
pr_xid.push(unescape(this_sub_sel.attr('data-xid')) + '/' + unescape(this_sub_sel.attr('data-nick')));
pr_xid.push(JappixCommon.unescapeQuotes(this_sub_sel.attr('data-xid')) + '/' + JappixCommon.unescapeQuotes(this_sub_sel.attr('data-nick')));
});
// Loop on XIDs
@ -2032,7 +2032,7 @@ var JappixMini = (function () {
var chat_pwd = MINI_SUGGEST_PASSWORDS[i] || '';
chans_html +=
'<a class="jm_suggest_groupchat" href="#" data-xid="' + escape(chat_room) + '" data-pwd="' + escape(chat_pwd) + '">' +
'<a class="jm_suggest_groupchat" href="#" data-xid="' + JappixCommon.escapeQuotes(chat_room) + '" data-pwd="' + JappixCommon.escapeQuotes(chat_pwd) + '">' +
'<span class="jm_chan_icon jm_images"></span>' +
'<span class="jm_chan_name">' + JappixCommon.getXIDNick(chat_room).htmlEnc() + '</span>' +
'</a>';
@ -2064,12 +2064,12 @@ var JappixMini = (function () {
if(!chat_nick) {
chat_nick = JappixCommon.getXIDNick(chat_xid);
} else {
chat_nick = unescape(chat_nick);
chat_nick = JappixCommon.unescapeQuotes(chat_nick);
}
// Generate HTML for current chat
chans_html +=
'<a class="jm_suggest_chat" href="#" data-xid="' + escape(chat_xid) + '">' +
'<a class="jm_suggest_chat" href="#" data-xid="' + JappixCommon.escapeQuotes(chat_xid) + '">' +
'<span class="jm_chan_icon jm_images"></span>' +
'<span class="jm_chan_name">' + JappixCommon.getXIDNick(chat_nick).htmlEnc() + '</span>' +
'</a>';
@ -2103,18 +2103,18 @@ var JappixMini = (function () {
// Chat?
if(this_sub_sel.is('.jm_suggest_chat')) {
var current_chat = unescape(this_sub_sel.attr('data-xid'));
var current_chat = JappixCommon.unescapeQuotes(this_sub_sel.attr('data-xid'));
self.chat('chat', current_chat, this_sub_sel.find('span.jm_chan_name').text(), hex_md5(current_chat));
}
// Groupchat?
else if(this_sub_sel.is('.jm_suggest_groupchat')) {
var current_groupchat = unescape(this_sub_sel.attr('data-xid'));
var current_groupchat = JappixCommon.unescapeQuotes(this_sub_sel.attr('data-xid'));
var current_password = this_sub_sel.attr('data-pwd') || null;
if(current_password)
current_password = unescape(current_password);
current_password = JappixCommon.unescapeQuotes(current_password);
self.chat('groupchat', current_groupchat, this_sub_sel.find('span.jm_chan_name').text(), hex_md5(current_groupchat), current_password);
}
@ -2194,7 +2194,7 @@ var JappixMini = (function () {
// Filter buddies
jQuery('#jappix_mini div.jm_roster div.jm_buddies a.jm_online').each(function() {
var this_sub_sel = jQuery(this);
var nick = unescape(this_sub_sel.data('nick'));
var nick = JappixCommon.unescapeQuotes(this_sub_sel.data('nick'));
if(nick.match(regex)) {
this_sub_sel.show();
@ -2380,7 +2380,7 @@ var JappixMini = (function () {
// Restore chat click events
jQuery('#jappix_mini div.jm_conversation').each(function() {
var this_sub_sel = jQuery(this);
self.chatEvents(this_sub_sel.attr('data-type'), unescape(this_sub_sel.attr('data-xid')), this_sub_sel.attr('data-hash'));
self.chatEvents(this_sub_sel.attr('data-type'), JappixCommon.unescapeQuotes(this_sub_sel.attr('data-xid')), this_sub_sel.attr('data-hash'));
});
// Restore init marker on all groupchats
@ -2447,7 +2447,7 @@ var JappixMini = (function () {
// Using a try/catch override IE issues
try {
var this_sel = jQuery(this);
self.chat('chat', unescape(this_sel.attr('data-xid')), unescape(this_sel.attr('data-nick')), this_sel.attr('data-hash'));
self.chat('chat', JappixCommon.unescapeQuotes(this_sel.attr('data-xid')), JappixCommon.unescapeQuotes(this_sel.attr('data-nick')), this_sel.attr('data-hash'));
}
catch(e) {}
@ -2866,7 +2866,7 @@ var JappixMini = (function () {
}
// Create the HTML markup
var html = '<div class="jm_conversation jm_type_' + type + '" id="chat-' + hash + '" data-xid="' + escape(xid) + '" data-type="' + type + '" data-nick="' + escape(nick) + '" data-hash="' + hash + '" data-origin="' + escape(JappixCommon.cutResource(xid)) + '">' +
var html = '<div class="jm_conversation jm_type_' + type + '" id="chat-' + hash + '" data-xid="' + JappixCommon.escapeQuotes(xid) + '" data-type="' + type + '" data-nick="' + JappixCommon.escapeQuotes(nick) + '" data-hash="' + hash + '" data-origin="' + JappixCommon.escapeQuotes(JappixCommon.cutResource(xid)) + '">' +
'<div class="jm_chat-content">' +
'<div class="jm_actions">' +
'<span class="jm_nick">' + nick + '</span>';
@ -2952,7 +2952,7 @@ var JappixMini = (function () {
// Join the groupchat
if(type == 'groupchat') {
// Add nickname & init values
jQuery(current).attr('data-nick', escape(nickname))
jQuery(current).attr('data-nick', JappixCommon.escapeQuotes(nickname))
.attr('data-init', 'false');
// Send the first groupchat presence
@ -3035,7 +3035,7 @@ var JappixMini = (function () {
// Quit the groupchat?
if(type == 'groupchat') {
// Send an unavailable presence
self.presence('unavailable', '', '', '', xid + '/' + unescape(current_sel.attr('data-nick')));
self.presence('unavailable', '', '', '', xid + '/' + JappixCommon.unescapeQuotes(current_sel.attr('data-nick')));
// Remove this groupchat!
self.removeGroupchat(xid);
@ -3221,7 +3221,7 @@ var JappixMini = (function () {
try {
// Remove the groupchat private chats & the groupchat buddies from the roster
jQuery('#jappix_mini div.jm_conversation[data-origin="' + escape(JappixCommon.cutResource(xid)) + '"], #jappix_mini div.jm_roster div.jm_grouped[data-xid="' + escape(xid) + '"]').remove();
jQuery('#jappix_mini div.jm_conversation[data-origin="' + JappixCommon.escapeQuotes(JappixCommon.cutResource(xid)) + '"], #jappix_mini div.jm_roster div.jm_grouped[data-xid="' + JappixCommon.escapeQuotes(xid) + '"]').remove();
// Update the presence counter
self.updateRoster();
@ -3282,7 +3282,7 @@ var JappixMini = (function () {
if(!chat_nick) {
chat_nick = JappixCommon.getXIDNick(chat_xid);
} else {
chat_nick = unescape(chat_nick);
chat_nick = JappixCommon.unescapeQuotes(chat_nick);
}
// Open the current chat
@ -3325,7 +3325,7 @@ var JappixMini = (function () {
// Group: start
if(c != MINI_ROSTER_NOGROUP) {
buddy_str += '<div class="jm_grouped jm_grouped_roster" data-name="' + escape(c) + '">';
buddy_str += '<div class="jm_grouped jm_grouped_roster" data-name="' + JappixCommon.escapeQuotes(c) + '">';
buddy_str += '<div class="jm_name">' + c.htmlEnc() + '</div>';
}
@ -3392,23 +3392,23 @@ var JappixMini = (function () {
// Generate the groupchat group path
if(groupchat) {
path = '#jappix_mini div.jm_roster div.jm_grouped_groupchat[data-xid="' + escape(bare_xid) + '"]';
path = '#jappix_mini div.jm_roster div.jm_grouped_groupchat[data-xid="' + JappixCommon.escapeQuotes(bare_xid) + '"]';
// Must add a groupchat group?
if(!JappixCommon.exists(path)) {
jQuery('#jappix_mini div.jm_roster div.jm_buddies').append(
'<div class="jm_grouped jm_grouped_groupchat" data-xid="' + escape(bare_xid) + '">' +
'<div class="jm_grouped jm_grouped_groupchat" data-xid="' + JappixCommon.escapeQuotes(bare_xid) + '">' +
'<div class="jm_name">' + JappixCommon.getXIDNick(groupchat).htmlEnc() + '</div>' +
'</div>'
);
}
} else if(group) {
path = '#jappix_mini div.jm_roster div.jm_grouped_roster[data-name="' + escape(group) + '"]';
path = '#jappix_mini div.jm_roster div.jm_grouped_roster[data-name="' + JappixCommon.escapeQuotes(group) + '"]';
// Must add a roster group?
if(!JappixCommon.exists(path)) {
jQuery('#jappix_mini div.jm_roster div.jm_buddies').append(
'<div class="jm_grouped jm_grouped_roster" data-name="' + escape(group) + '">' +
'<div class="jm_grouped jm_grouped_roster" data-name="' + JappixCommon.escapeQuotes(group) + '">' +
'<div class="jm_name">' + group.htmlEnc() + '</div>' +
'</div>'
);
@ -3465,8 +3465,8 @@ var JappixMini = (function () {
buddy_str += '<a class="jm_friend jm_offline jm_friend-' + hash;
buddy_str += '" id="friend-' + hash;
buddy_str += '" title="' + JappixCommon.encodeQuotes(xid) + '"';
buddy_str += '" data-xid="' + escape(xid) + '"';
buddy_str += '" data-nick="' + escape(nick) + '"';
buddy_str += '" data-xid="' + JappixCommon.escapeQuotes(xid) + '"';
buddy_str += '" data-nick="' + JappixCommon.escapeQuotes(nick) + '"';
buddy_str += '" data-hash="' + hash + '"';
buddy_str += ' ' + (subscription ? ' data-sub="' + subscription + '" ' : '');
buddy_str += '>';
@ -3501,7 +3501,7 @@ var JappixMini = (function () {
jQuery('#jappix_mini a#friend-' + hash).remove();
// Empty group?
var group = '#jappix_mini div.jm_roster div.jm_grouped_groupchat[data-xid="' + escape(groupchat) + '"]';
var group = '#jappix_mini div.jm_roster div.jm_grouped_groupchat[data-xid="' + JappixCommon.escapeQuotes(groupchat) + '"]';
if(groupchat && !jQuery(group + ' a.jm_friend').size()) {
jQuery(group).remove();
@ -3962,8 +3962,8 @@ var JappixMini = (function () {
jQuery('#jappix_mini').append(
'<div id="jm_audio">' +
'<audio preload="auto">' +
'<source src="' + JAPPIX_STATIC + 'snd/receive-message.mp3" />' +
'<source src="' + JAPPIX_STATIC + 'snd/receive-message.oga" />' +
'<source src="' + JAPPIX_STATIC + 'sounds/receive-message.mp3" />' +
'<source src="' + JAPPIX_STATIC + 'sounds/receive-message.oga" />' +
'</audio>' +
'</div>'
);
@ -4185,7 +4185,7 @@ var JappixMini = (function () {
// Append final stylesheet HTML
for(var u in css_url) {
css_html += '<link rel="stylesheet" href="' + JappixCommon.encodeQuotes(css_url[u]) + '" type="text/css" media="all" />';
css_html += '<link rel="stylesheet" href="' + JappixCommon.encodeQuotes(css_url[u].replace(/&amp;/g, '&')) + '" type="text/css" media="all" />';
}
jQuery('head').append(css_html);

View file

@ -47,10 +47,8 @@ var Mobile = (function () {
return false;
}
}
// No "@" in the XID, we should add the default domain
else {
} else {
// No "@" in the XID, we should add the default domain
username = xid;
domain = HOST_MAIN;
}
@ -58,8 +56,9 @@ var Mobile = (function () {
var pwd = aForm.pwd.value;
var reg = false;
if(aForm.reg)
if(aForm.reg) {
reg = aForm.reg.checked;
}
// Enough parameters
if(username && domain && pwd) {
@ -141,6 +140,30 @@ var Mobile = (function () {
};
/**
* Proceeds client initialization
* @public
* @return {undefined}
*/
self.doInitialize = function() {
try {
if(typeof HTTP_AUTH === 'object' &&
HTTP_AUTH.user && HTTP_AUTH.password && HTTP_AUTH.host) {
var form_sel = document.forms['login-form'];
form_sel.elements.xid.value = (HTTP_AUTH.user + '@' + HTTP_AUTH.host);
form_sel.elements.pwd.value = HTTP_AUTH.password;
self.doLogin(form_sel);
}
} catch(e) {
Console.error('Mobile.doInitialize', e);
}
};
/**
* Shows target element
* @public
@ -308,8 +331,9 @@ var Mobile = (function () {
var nick = self.getNick(xid, hash);
// No nickname?
if(!nick)
if(!nick) {
nick = xid;
}
// Create the chat if it does not exist
self.chat(xid, nick);
@ -340,10 +364,8 @@ var Mobile = (function () {
var type = pre.getType();
var show = pre.getShow();
// Online buddy: show it!
// Online buddy
if(!type) {
self.showThis('buddy-' + hash);
// Display the correct presence
switch(show) {
case 'chat':
@ -366,8 +388,6 @@ var Mobile = (function () {
self.displayPresence(hash, 'available');
break;
}
} else {
self.hideThis('buddy-' + hash);
}
} catch(e) {
Console.error('Mobile.handlePresence', e);
@ -538,7 +558,9 @@ var Mobile = (function () {
return self.sendPresence('', 'available', 1);
// Define some pre-vars
var current, xid, nick, oneBuddy, oneID, hash;
var current, xid, nick, oneBuddy, oneID, hash, cur_buddy;
var roster_buddies = [];
var roster = document.getElementById('roster');
// Get roster items
@ -554,18 +576,30 @@ var Mobile = (function () {
hash = hex_md5(xid);
// No defined nick?
if(!nick)
if(!nick) {
nick = self.getDirectNick(xid);
// Display the values
oneBuddy = document.createElement('a');
oneID = 'buddy-' + hash;
oneBuddy.setAttribute('href', '#');
oneBuddy.setAttribute('id', oneID);
oneBuddy.setAttribute('class', 'one-buddy');
oneBuddy.setAttribute('onclick', 'return Mobile.chat(\'' + self.encodeOnclick(xid) + '\', \'' + self.encodeOnclick(nick) + '\');');
oneBuddy.innerHTML = nick.htmlEnc();
roster.appendChild(oneBuddy);
}
roster_buddies.push({
'xid': xid,
'hash': hash,
'nick': nick
});
}
// Sort the values
self.sortRoster(roster_buddies);
// Display the values
for(var j = 0; j < roster_buddies.length; j++) {
cur_buddy = roster_buddies[j];
self.displayRoster(
roster,
cur_buddy.xid,
cur_buddy.hash,
cur_buddy.nick
);
}
// Start handling buddies presence
@ -721,10 +755,11 @@ var Mobile = (function () {
// 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
@ -831,10 +866,11 @@ var Mobile = (function () {
// Display the message
html = '<span><b';
if(nick == 'me')
if(nick == 'me') {
html += ' class="me">' + self._e("You");
else
} else {
html += ' class="him">' + nick;
}
html += '</b> ' + self.filter(body) + '</span>';
@ -849,6 +885,61 @@ var Mobile = (function () {
};
/**
* Displays a roster buddy
* @public
* @param {object} roster
* @param {string} xid
* @param {string} hash
* @param {string} nick
* @return {undefined}
*/
self.displayRoster = function(roster, xid, hash, nick) {
try {
oneBuddy = document.createElement('a');
oneID = 'buddy-' + hash;
oneBuddy.setAttribute('href', '#');
oneBuddy.setAttribute('id', oneID);
oneBuddy.setAttribute('class', 'one-buddy');
oneBuddy.setAttribute('onclick', 'return Mobile.chat(\'' + self.encodeOnclick(xid) + '\', \'' + self.encodeOnclick(nick) + '\');');
oneBuddy.innerHTML = nick.htmlEnc();
roster.appendChild(oneBuddy);
} catch(e) {
Console.error('Mobile.displayRoster', e);
}
};
/**
* Sorts the roster buddies by nickname
* @public
* @param {object} roster_buddies
* @return {object}
*/
self.sortRoster = function(roster_buddies) {
try {
var one_nick, two_nick;
roster_buddies.sort(function(one, two) {
one_nick = (one.nick + '').toLowerCase();
two_nick = (two.nick + '').toLowerCase();
return one_nick < two_nick ? -1 : (one_nick > two_nick ? 1 : 0);
});
} catch(e) {
Console.error('Mobile.sortRoster', e);
} finally {
return roster_buddies;
}
};
/**
* Goes back to roster view
* @public
@ -885,8 +976,9 @@ var Mobile = (function () {
var divs = document.getElementsByTagName('div');
for(var i = 0; i < divs.length; i++) {
if(divs.item(i).getAttribute('class') == 'one-chat')
if(divs.item(i).getAttribute('class') == 'one-chat') {
divs.item(i).style.display = 'none';
}
}
// Show the chat
@ -941,8 +1033,9 @@ var Mobile = (function () {
// If the chat was not yet opened
if(!self.exists('chat-' + hash)) {
// No nick?
if(!nick)
if(!nick) {
nick = self.getNick(xid, hash);
}
// Create the chat
self.createChat(xid, nick, hash);
@ -990,6 +1083,7 @@ var Mobile = (function () {
try {
onbeforeunload = self.doLogout;
onload = self.doInitialize;
} catch(e) {
Console.error('Mobile.launch', e);
}

View file

@ -154,6 +154,7 @@ var MUCAdmin = (function () {
self.query(xid, 'owner');
self.query(xid, 'admin');
self.query(xid, 'outcast');
// We query the room to edit
DataForm.go(xid, 'muc', '', '', 'mucadmin');
} else if(aff == 'admin') {
@ -434,8 +435,9 @@ var MUCAdmin = (function () {
Board.openThisInfo(5);
// We remove the user's favorite
if(DataStore.existDB('favorites', room))
if(DataStore.existDB(Connection.desktop_hash, 'favorites', room)) {
Favorites.removeThis(room, Common.explodeThis('@', room, 0));
}
Console.info('MUC admin destroyed: ' + room);
}
@ -555,10 +557,13 @@ var MUCAdmin = (function () {
try {
// Click events
$('#mucadmin .bottom .finish').click(function() {
if($(this).is('.cancel'))
if($(this).is('.cancel')) {
return self.close();
if($(this).is('.save'))
}
if($(this).is('.save')) {
return self.save();
}
});
} catch(e) {
Console.error('MUCAdmin.instance', e);

File diff suppressed because it is too large Load diff

View file

@ -63,34 +63,30 @@ var Music = (function () {
if(!Common.exists(path_type)) {
var code = '<div class="' + type + '"></div>';
if(type == 'local')
if(type == 'local') {
$(content).prepend(code);
else
} else {
$(content).append(code);
}
}
// Fill the results
$(xml).find('track').each(function() {
// Parse the XML
var id = $(this).find('id').text();
var title = $(this).find('name').text();
var artist = $(this).find('artist').text();
var source = $(this).find('source').text();
var duration = $(this).find('duration').text();
var uri = $(this).find('url').text();
var mime = $(this).find('type').text();
// No ID?
if(!id)
id = hex_md5(uri);
// No MIME?
if(!mime)
mime = 'audio/ogg';
var this_sel = $(this);
var id = this_sel.find('id').text() || hex_md5(uri);
var title = this_sel.find('name').text();
var artist = this_sel.find('artist').text();
var source = this_sel.find('source').text();
var duration = this_sel.find('duration').text();
var uri = this_sel.find('url').text();
var mime = this_sel.find('type').text() || 'audio/ogg';
// Local URL?
if(type == 'local')
if(type == 'local') {
uri = Utils.generateURL(uri);
}
// Append the HTML code
$(path_type).append('<a href="#" class="song" data-id="' + id + '">' + title + '</a>');
@ -98,8 +94,9 @@ var Music = (function () {
// Current playing song?
var current_song = $(path_type + ' a[data-id="' + id + '"]');
if(Common.exists('.music-audio[data-id="' + id + '"]'))
if(Common.exists('.music-audio[data-id="' + id + '"]')) {
current_song.addClass('playing');
}
// Click event
current_song.click(function() {
@ -117,12 +114,14 @@ var Music = (function () {
$(path + 'input').val('').removeAttr('disabled');
// No result
if(!jamendo && !local)
if(!jamendo && !local) {
$(path + '.no-results').show();
}
// We must put a separator between the categories
if(jamendo && local)
if(jamendo && local) {
$(content + ' .local').addClass('special');
}
}
} catch(e) {
Console.error('Music.parse', e);
@ -157,7 +156,10 @@ var Music = (function () {
});
// Get the local results
$.get('./server/music-search.php', {searchquery: string, location: JAPPIX_LOCATION}, function(data) {
$.get('./server/music-search.php', {
searchquery: string,
location: JAPPIX_LOCATION
}, function(data) {
self.parse(data, 'local');
});
} catch(e) {
@ -177,33 +179,35 @@ var Music = (function () {
try {
// Initialize
var playThis = document.getElementById('top-content').getElementsByTagName('audio')[0];
var audio_sel = document.getElementById('top-content').getElementsByTagName('audio')[0];
// Nothing to play, exit
if(!playThis)
if(!audio_sel) {
return false;
}
var stopButton = $('#top-content a.stop');
// User play a song
if(action == 'play') {
stopButton.show();
playThis.load();
playThis.play();
playThis.addEventListener('ended', function() {
audio_sel.load();
audio_sel.play();
audio_sel.addEventListener('ended', function() {
self.action('stop');
}, true);
Console.log('Music is now playing.');
}
// User stop the song or the song came to its end
else if(action == 'stop') {
} else if(action == 'stop') {
// User stop the song / end of song
stopButton.hide();
playThis.pause();
audio_sel.pause();
$('#top-content .music').removeClass('actived');
$('.music-content .list a').removeClass('playing');
$('.music-audio').remove();
self.publish();
Console.log('Music is now stopped.');
@ -245,27 +249,24 @@ var Music = (function () {
// Enough data?
if(title || artist || source || uri) {
// Data array
var nodes = new Array(
'title',
'artist',
'source',
'length',
'uri'
);
var values = new Array(
title,
artist,
source,
length,
uri
);
var music_data = {
'title': title,
'artist': artist,
'source': source,
'length': length,
'uri': uri
};
// Create the children nodes
for(var i in nodes) {
if(values[i]) {
tune.appendChild(iq.buildNode(nodes[i], {'xmlns': NS_TUNE}, values[i]));
var cur_value;
for(var cur_name in music_data) {
cur_value = music_data[cur_name];
if(cur_value) {
tune.appendChild(iq.buildNode(cur_name, {
'xmlns': NS_TUNE
}, cur_value));
}
}
}
@ -298,16 +299,18 @@ var Music = (function () {
try {
var path = '.music-content ';
var music_audio_sel = $('.music-audio');
// We remove & create a new audio tag
$('.music-audio').remove();
music_audio_sel.remove();
$(path + '.player').prepend('<audio class="music-audio" type="' + mime + '" data-id="' + id + '" />');
// We apply the new source to the player
if(type == 'jamendo')
$('.music-audio').attr('src', 'http://api.jamendo.com/get2/stream/track/redirect/?id=' + id + '&streamencoding=ogg2');
else
$('.music-audio').attr('src', uri);
if(type == 'jamendo') {
music_audio_sel.attr('src', 'http://api.jamendo.com/get2/stream/track/redirect/?id=' + id + '&streamencoding=ogg2');
} else {
music_audio_sel.attr('src', uri);
}
// We play the target sound
self.action('play');

View file

@ -53,8 +53,9 @@ var Name = (function () {
try {
// Was it an obsolete request?
if(!Common.exists('.add-contact-name-get[data-for="' + escape(Common.bareXID(Common.getStanzaFrom(iq))) + '"]'))
if(!Common.exists('.add-contact-name-get[data-for="' + escape(Common.bareXID(Common.getStanzaFrom(iq))) + '"]')) {
return false;
}
// Reset the waiting item
$('.add-contact-name-get').hide().removeAttr('data-for');
@ -63,8 +64,9 @@ var Name = (function () {
if(iq.getType() == 'result') {
var full_name = self.generateBuddy(iq)[0];
if(full_name)
if(full_name) {
$('.add-contact-name').val(full_name);
}
}
} catch(e) {
Console.error('Name.handleAddUser', e);
@ -85,16 +87,16 @@ var Name = (function () {
try {
// Get the IQ content
var xml = $(iq.getNode()).find('vCard');
var vcard_sel = $(iq.getNode()).find('vCard');
// Get the full name & the nickname
var pFull = xml.find('FN:first').text();
var pNick = xml.find('NICKNAME:first').text();
var pFull = vcard_sel.find('FN:first').text();
var pNick = vcard_sel.find('NICKNAME:first').text();
// No full name?
if(!pFull) {
// Get the given name
var pN = xml.find('N:first');
var pN = vcard_sel.find('N:first');
var pGiven = pN.find('GIVEN:first').text();
if(pGiven) {
@ -103,8 +105,9 @@ var Name = (function () {
// Get the family name (optional)
var pFamily = pN.find('FAMILY:first').text();
if(pFamily)
if(pFamily) {
pFull += ' ' + pFamily;
}
}
}
@ -132,22 +135,22 @@ var Name = (function () {
xid = Common.bareXID(xid);
// This is me?
if(Utils.isAnonymous() && !xid)
if(Utils.isAnonymous() && !xid) {
bname = Common._e("You");
else if(xid == Common.getXID())
} else if(xid == Common.getXID()) {
bname = self.get();
}
// Not me!
else {
cname = $('#roster .buddy[data-xid="' + escape(xid) + '"]:first .buddy-name').html();
// If the complete name exists
if(cname)
// Complete name exists?
if(cname) {
bname = cname.revertHtmlEnc();
// Else, we just get the nickname of the buddy
else
} else {
bname = Common.getXIDNick(xid);
}
}
return bname;
@ -170,8 +173,9 @@ var Name = (function () {
var nick = DataStore.getDB(Connection.desktop_hash, 'profile', 'nick');
// No nick?
if(!nick)
if(!nick) {
nick = con.username;
}
return nick;
} catch(e) {
@ -192,9 +196,10 @@ var Name = (function () {
// Try to read the user name
var name = DataStore.getDB(Connection.desktop_hash, 'profile', 'name');
// No name? Use the nickname instead!
if(!name)
// No name? Use the nickname instead
if(!name) {
name = self.getNick();
}
return name;
} catch(e) {

View file

@ -62,10 +62,7 @@ var Notification = (function () {
$(notif).prepend('<div class="notify one-counter" data-counter="' + number + '">' + number + '</div>');
$(nothing).hide();
$(empty).show();
}
// No notification!
else {
} else {
$(empty).hide();
$(nothing).show();
@ -96,8 +93,9 @@ var Notification = (function () {
self.create = function(type, from, data, body, id, inverse) {
try {
if(!type || !from)
if(!type || !from) {
return;
}
// Generate an ID hash
if(!id) {
@ -229,8 +227,9 @@ var Notification = (function () {
}
// No text?
if(!text)
if(!text) {
return;
}
// Action links?
switch(type) {
@ -248,8 +247,9 @@ var Notification = (function () {
action = '<a href="#" class="no">' + Common._e("Hide") + '</a>';
// Any parent link?
if((type == 'comment') && data[2])
if((type == 'comment') && data[2]) {
action = '<a href="#" class="yes">' + Common._e("Show") + '</a>' + action;
}
break;
@ -284,10 +284,11 @@ var Notification = (function () {
'</div>';
// Add the HTML code
if(inverse)
if(inverse) {
$('.notifications-content .nothing').before(code);
else
} else {
$('.notifications-content .empty').after(code);
}
// Play a sound to alert the user
Audio.play('notification');
@ -296,8 +297,9 @@ var Notification = (function () {
$('.' + id + ' a.yes').click(function() {
self.action(type, data, 'yes', id);
if(($(this).attr('href') == '#') && ($(this).attr('target') != '_blank'))
if(($(this).attr('href') == '#') && ($(this).attr('target') != '_blank')) {
return false;
}
});
// The no click function
@ -334,28 +336,23 @@ var Notification = (function () {
try {
// We launch a function depending of the type
if((type == 'subscribe') && (value == 'yes'))
if((type == 'subscribe') && (value == 'yes')) {
Presence.acceptSubscribe(data[0], data[1]);
else if((type == 'subscribe') && (value == 'no'))
} else if((type == 'subscribe') && (value == 'no')) {
Presence.sendSubscribe(data[0], 'unsubscribed');
else if((type == 'invite_room') && (value == 'yes'))
} else if((type == 'invite_room') && (value == 'yes')) {
Chat.checkCreate(data[0], 'groupchat');
else if(type == 'request')
} else if(type == 'request') {
HTTPReply.go(value, data[0]);
}
if((type == 'send') && (value == 'yes'))
if((type == 'send') && (value == 'yes')) {
OOB.reply(data[0], data[3], 'accept', data[2], data[4]);
else if((type == 'send') && (value == 'no'))
} else if((type == 'send') && (value == 'no')) {
OOB.reply(data[0], data[3], 'reject', data[2], data[4]);
else if((type == 'rosterx') && (value == 'yes'))
} else if((type == 'rosterx') && (value == 'yes')) {
RosterX.open(data[0]);
else if((type == 'comment') || (type == 'like') || (type == 'quote') || (type == 'wall') || (type == 'photo') || (type == 'video')) {
} else if((type == 'comment') || (type == 'like') || (type == 'quote') || (type == 'wall') || (type == 'photo') || (type == 'video')) {
if(value == 'yes') {
// Get the microblog item
Microblog.fromInfos(data[2]);
@ -452,25 +449,29 @@ var Notification = (function () {
// Should we inverse?
var inverse = true;
if(items.size() == 1)
if(items.size() == 1) {
inverse = false;
}
// Parse notifications
items.each(function() {
var this_sel = $(this);
// Parse the current item
var current_item = $(this).attr('id');
var current_type = $(this).find('link[rel="via"]:first').attr('title');
var current_href = $(this).find('link[rel="via"]:first').attr('href');
var current_parent_href = $(this).find('link[rel="related"]:first').attr('href');
var current_xid = Common.explodeThis(':', $(this).find('author uri').text(), 1);
var current_name = $(this).find('author name').text();
var current_text = $(this).find('content[type="text"]:first').text();
var current_item = this_sel.attr('id');
var current_type = this_sel.find('link[rel="via"]:first').attr('title');
var current_href = this_sel.find('link[rel="via"]:first').attr('href');
var current_parent_href = this_sel.find('link[rel="related"]:first').attr('href');
var current_xid = Common.explodeThis(':', this_sel.find('author uri').text(), 1);
var current_name = this_sel.find('author name').text();
var current_text = this_sel.find('content[type="text"]:first').text();
var current_bname = Name.getBuddy(current_xid);
var current_id = hex_md5(current_type + current_xid + current_href + current_text);
// Choose the good name!
if(!current_name || (current_bname != Common.getXIDNick(current_xid)))
if(!current_name || (current_bname != Common.getXIDNick(current_xid))) {
current_name = current_bname;
}
// Create it!
self.create(current_type, current_xid, [current_name, current_href, current_parent_href, current_item], current_text, current_id, inverse);

View file

@ -39,8 +39,9 @@ var OOB = (function () {
to = Caps.getFeatureResource(to, NS_IQOOB);
// IQs cannot be sent to offline users
if(!to)
if(!to) {
return;
}
// Register the ID
DataStore.setDB(Connection.desktop_hash, 'send/url', id, url);
@ -92,19 +93,15 @@ var OOB = (function () {
self.handle = function(from, id, type, node) {
try {
var xid = '';
var url = '';
var desc = '';
var xid = '', url = '', desc = '';
// IQ stanza?
if(type == 'iq') {
// IQ stanza
xid = Common.fullXID(from);
url = $(node).find('url').text();
desc = $(node).find('desc').text();
}
// Message stanza?
else {
} else {
// Message stanza
xid = Common.bareXID(from);
url = $(node).find('url').text();
desc = $(node).find('body').text();
@ -140,8 +137,9 @@ var OOB = (function () {
try {
// Not IQ type?
if(type != 'iq')
if(type != 'iq') {
return;
}
// New IQ
var aIQ = new JSJaCIQ();
@ -160,11 +158,17 @@ var OOB = (function () {
aIQ.setType('error');
// Append stanza content
for(var i = 0; i < node.childNodes.length; i++)
for(var i = 0; i < node.childNodes.length; i++) {
aIQ.getNode().appendChild(node.childNodes.item(i).cloneNode(true));
}
// Append error content
var aError = aIQ.appendNode('error', {'xmlns': NS_CLIENT, 'code': '406', 'type': 'modify'});
var aError = aIQ.appendNode('error', {
'xmlns': NS_CLIENT,
'code': '406',
'type': 'modify'
});
aError.appendChild(aIQ.buildNode('not-acceptable', {'xmlns': NS_STANZAS}));
Console.info('Rejected file request from: ' + to);
@ -187,11 +191,16 @@ var OOB = (function () {
try {
// Append the wait icon
$('#page-engine .chat-tools-file:not(.mini) .tooltip-subitem *').hide();
$('#page-engine .chat-tools-file:not(.mini) .tooltip-subitem').append('<div class="wait wait-medium"></div>');
var chat_tools_file_sel = page_engine_sel.find('.chat-tools-file:not(.mini)');
var subitem_sel = chat_tools_file_sel.find('.tooltip-subitem');
subitem_sel.find('*').hide();
subitem_sel.append(
'<div class="wait wait-medium"></div>'
);
// Lock the bubble
$('#page-engine .chat-tools-file:not(.mini)').addClass('mini');
chat_tools_file_sel.addClass('mini');
} catch(e) {
Console.error('OOB.waitUpload', e);
}
@ -208,6 +217,8 @@ var OOB = (function () {
self.handleUpload = function(responseXML) {
try {
var page_engine_sel = $('#page-engine');
// Data selector
var dData = $(responseXML).find('jappix');
@ -220,25 +231,27 @@ var OOB = (function () {
var oob_has;
// No ID provided?
if(!fID)
if(!fID) {
oob_has = ':has(.wait)';
else
} else {
oob_has = ':has(#oob-upload input[value="' + fID + '"])';
}
var xid = $('#page-engine .page-engine-chan' + oob_has).attr('data-xid');
var oob_type = $('#page-engine .chat-tools-file' + oob_has).attr('data-oob');
var xid = page_engine_sel.find('.page-engine-chan' + oob_has).attr('data-xid');
var oob_type = page_engine_sel.find('.chat-tools-file' + oob_has).attr('data-oob');
// Reset the file send tool
$('#page-engine .chat-tools-file' + oob_has).removeClass('mini');
$('#page-engine .bubble-file' + oob_has).remove();
page_engine_sel.find('.chat-tools-file' + oob_has).removeClass('mini');
page_engine_sel.find('.bubble-file' + oob_has).remove();
// Not available?
if($('#page-engine .chat-tools-file' + oob_has).is(':hidden') && (oob_type == 'iq')) {
if(page_engine_sel.find('.chat-tools-file' + oob_has).is(':hidden') && (oob_type == 'iq')) {
Board.openThisError(4);
// Remove the file we sent
if(fURL)
if(fURL) {
$.get(fURL + '&action=remove');
}
}
// Everything okay?
@ -250,10 +263,7 @@ var OOB = (function () {
Notification.create('send_pending', xid, [xid, fURL, oob_type, '', ''], fDesc, hex_md5(fURL + fDesc + fID));
Console.info('File request sent.');
}
// Upload error?
else {
} else {
Board.openThisError(4);
Console.error('Error while sending the file', dData.find('error').text());

View file

@ -275,11 +275,13 @@ var Options = (function () {
self.switchTab = function(id) {
try {
$('#options .one-lap').hide();
$('#options #conf' + id).show();
$('#options .tab a').removeClass('tab-active');
$('#options .tab a[data-key="' + id + '"]').addClass('tab-active');
$('#options .sub-ask .sub-ask-close').click();
var options_sel = $('#options');
options_sel.find('.one-lap').hide();
options_sel.find('#conf' + id).show();
options_sel.find('.tab a').removeClass('tab-active');
options_sel.find('.tab a[data-key="' + id + '"]').addClass('tab-active');
options_sel.find('.sub-ask .sub-ask-close').click();
} catch(e) {
Console.error('Options.switchTab', e);
} finally {
@ -298,15 +300,16 @@ var Options = (function () {
self.wait = function(id) {
try {
var sOptions = $('#options .content');
var options_sel = $('#options');
var content_sel = options_sel.find('.content');
// Remove the current item class
sOptions.removeClass(id);
content_sel.removeClass(id);
// Hide the waiting items if all was received
if(!sOptions.hasClass('microblog') && !sOptions.hasClass('mam')) {
$('#options .wait').hide();
$('#options .finish:first').removeClass('disabled');
if(!content_sel.hasClass('microblog') && !content_sel.hasClass('mam')) {
options_sel.find('.wait').hide();
options_sel.find('.finish:first').removeClass('disabled');
}
} catch(e) {
Console.error('Options.wait', e);
@ -533,22 +536,26 @@ var Options = (function () {
$('.sub-ask-pass input').each(function() {
var select = $(this);
if(!select.val())
if(!select.val()) {
$(document).oneTime(10, function() {
select.addClass('please-complete').focus();
});
else
} else {
select.removeClass('please-complete');
}
});
if(password0 != Utils.getPassword())
if(password0 != Utils.getPassword()) {
$(document).oneTime(10, function() {
$('#options .old').addClass('please-complete').focus();
});
if(password1 != password2)
}
if(password1 != password2) {
$(document).oneTime(10, function() {
$('#options .new1, #options .new2').addClass('please-complete').focus();
});
}
}
} catch(e) {
Console.error('Options.sendNewPassword', e);
@ -612,12 +619,13 @@ var Options = (function () {
} else {
var selector = $('#options .check-mam');
if(password != Utils.getPassword())
if(password != Utils.getPassword()) {
$(document).oneTime(10, function() {
selector.addClass('please-complete').focus();
});
else
} else {
selector.removeClass('please-complete');
}
}
} catch(e) {
Console.error('Options.purgeMyArchives', e);
@ -659,12 +667,13 @@ var Options = (function () {
} else {
var selector = $('#options .check-empty');
if(password != Utils.getPassword())
if(password != Utils.getPassword()) {
$(document).oneTime(10, function() {
selector.addClass('please-complete').focus();
});
else
} else {
selector.removeClass('please-complete');
}
}
} catch(e) {
Console.error('Options.purgeMyMicroblog', e);
@ -726,17 +735,16 @@ var Options = (function () {
con.send(iq, self.handleAccDeletion);
Console.info('Delete account sent.');
}
else {
} else {
var selector = $('#options .check-password');
if(password != Utils.getPassword())
if(password != Utils.getPassword()) {
$(document).oneTime(10, function() {
selector.addClass('please-complete').focus();
});
else
} else {
selector.removeClass('please-complete');
}
}
} catch(e) {
Console.error('Options.deleteMyAccount', e);
@ -781,50 +789,58 @@ var Options = (function () {
}
// We show the "privacy" form if something is visible into it
if(enabled_mam || enabled_pep)
if(enabled_mam || enabled_pep) {
$('#options fieldset.privacy').show();
}
// We get the values of the forms for the sounds
if(DataStore.getDB(Connection.desktop_hash, 'options', 'sounds') == '0')
if(DataStore.getDB(Connection.desktop_hash, 'options', 'sounds') == '0') {
$('#sounds').attr('checked', false);
else
} else {
$('#sounds').attr('checked', true);
}
// We get the values of the forms for the geolocation
if(DataStore.getDB(Connection.desktop_hash, 'options', 'geolocation') == '1')
if(DataStore.getDB(Connection.desktop_hash, 'options', 'geolocation') == '1') {
$('#geolocation').attr('checked', true);
else
} else {
$('#geolocation').attr('checked', false);
}
// We get the values of the forms for the roster show all
if(DataStore.getDB(Connection.desktop_hash, 'options', 'roster-showall') == '1')
if(DataStore.getDB(Connection.desktop_hash, 'options', 'roster-showall') == '1') {
$('#showall').attr('checked', true);
else
} else {
$('#showall').attr('checked', false);
}
// We get the values of the forms for the XHTML-IM images filter
if(DataStore.getDB(Connection.desktop_hash, 'options', 'no-xhtml-images') == '1')
if(DataStore.getDB(Connection.desktop_hash, 'options', 'no-xhtml-images') == '1') {
$('#noxhtmlimg').attr('checked', true);
else
} else {
$('#noxhtmlimg').attr('checked', false);
}
// We get the values of the forms for the integratemedias
if(DataStore.getDB(Connection.desktop_hash, 'options', 'integratemedias') == '0')
if(DataStore.getDB(Connection.desktop_hash, 'options', 'integratemedias') == '0') {
$('#integratemedias').attr('checked', false);
else
} else {
$('#integratemedias').attr('checked', true);
}
// We get the values of the forms for the groupchatpresence
if(DataStore.getDB(Connection.desktop_hash, 'options', 'groupchatpresence') == '0')
if(DataStore.getDB(Connection.desktop_hash, 'options', 'groupchatpresence') == '0') {
$('#groupchatpresence').attr('checked', false);
else
} else {
$('#groupchatpresence').attr('checked', true);
}
// We get the values of the forms for the localarchives
if(DataStore.getDB(Connection.desktop_hash, 'options', 'localarchives') == '0')
if(DataStore.getDB(Connection.desktop_hash, 'options', 'localarchives') == '0') {
$('#localarchives').attr('checked', false);
else
} else {
$('#localarchives').attr('checked', true);
}
} catch(e) {
Console.error('Options.load', e);
}
@ -939,10 +955,13 @@ var Options = (function () {
});
$('#options .bottom .finish').click(function() {
if($(this).is('.save') && !$(this).hasClass('disabled'))
if($(this).is('.save') && !$(this).hasClass('disabled')) {
return self.save();
if($(this).is('.cancel'))
}
if($(this).is('.cancel')) {
return self.close();
}
return false;
});
@ -951,20 +970,24 @@ var Options = (function () {
$('#options .sub-ask input').keyup(function(e) {
if(e.keyCode == 13) {
// Archives purge
if($(this).is('.purge-archives'))
if($(this).is('.purge-archives')) {
return self.purgeMyArchives();
}
// Microblog purge
else if($(this).is('.purge-microblog'))
else if($(this).is('.purge-microblog')) {
return self.purgeMyMicroblog();
}
// Password change
else if($(this).is('.password-change'))
else if($(this).is('.password-change')) {
return self.sendNewPassword();
}
// Account deletion
else if($(this).is('.delete-account'))
else if($(this).is('.delete-account')) {
return self.deleteMyAccount();
}
}
});

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -215,16 +215,18 @@ var Privacy = (function () {
// Any block list?
if($(iqQuery).find('list[name="block"]').size()) {
// Not the default one?
if(!$(iqQuery).find('default[name="block"]').size())
if(!$(iqQuery).find('default[name="block"]').size()) {
self.change('block', 'default');
else
} else {
DataStore.setDB(Connection.desktop_hash, 'privacy-marker', 'default', 'block');
}
// Not the active one?
if(!$(iqQuery).find('active[name="block"]').size())
if(!$(iqQuery).find('active[name="block"]').size()) {
self.change('block', 'active');
else
} else {
DataStore.setDB(Connection.desktop_hash, 'privacy-marker', 'active', 'block');
}
// Get the block list rules
self.get('block');
@ -381,10 +383,11 @@ var Privacy = (function () {
}
con.send(iq, function(iq) {
if(iq.getType() == 'result')
if(iq.getType() == 'result') {
Console.log('Sent privacy list.');
else
} else {
Console.error('Error sending privacy list.');
}
});
Console.log('Sending privacy list: ' + list);
@ -455,8 +458,9 @@ var Privacy = (function () {
if(!c_order)
c_order = '';
if(!isNaN(c_order) && parseInt(c_order) > highest_order)
if(!isNaN(c_order) && parseInt(c_order) > highest_order) {
highest_order = parseInt(c_order);
}
type.push(c_type);
value.push(c_value);
@ -464,25 +468,29 @@ var Privacy = (function () {
order.push(c_order);
// Child elements
if($(this).find('presence-in').size())
if($(this).find('presence-in').size()) {
presence_in.push(true);
else
} else {
presence_in.push(false);
}
if($(this).find('presence-out').size())
if($(this).find('presence-out').size()) {
presence_out.push(true);
else
} else {
presence_out.push(false);
}
if($(this).find('message').size())
if($(this).find('message').size()) {
msg.push(true);
else
} else {
msg.push(false);
}
if($(this).find('iq').size())
if($(this).find('iq').size()) {
iq_p.push(true);
else
} else {
iq_p.push(false);
}
}
});
@ -508,8 +516,9 @@ var Privacy = (function () {
try {
// Yet sent?
if(DataStore.getDB(Connection.desktop_hash, 'privacy-marker', status) == list)
if(DataStore.getDB(Connection.desktop_hash, 'privacy-marker', status) == list) {
return;
}
// Write a marker
DataStore.setDB(Connection.desktop_hash, 'privacy-marker', status, list);
@ -523,8 +532,9 @@ var Privacy = (function () {
var iqStatus = iqQuery.appendChild(iq.buildNode(status, {'xmlns': NS_PRIVACY}));
// Can add a "name" attribute?
if(list)
if(list) {
iqStatus.setAttribute('name', list);
}
con.send(iq);
@ -596,18 +606,20 @@ var Privacy = (function () {
$(data).find('list').each(function() {
var list_name = $(this).attr('name');
if(list_name)
if(list_name) {
code += '<option value="' + Common.encodeQuotes(list_name) + '">' + list_name.htmlEnc() + '</option>';
}
});
// Apply HTML code
select.html(code);
// Not empty?
if(code)
if(code) {
select.removeAttr('disabled');
else
} else {
select.attr('disabled', true);
}
} catch(e) {
Console.error('Privacy.displayLists', e);
} finally {
@ -638,8 +650,9 @@ var Privacy = (function () {
select.html('');
// No list?
if(!list)
if(!list) {
return false;
}
// Reset the list status
$('#privacy .privacy-active input[type="checkbox"]').removeAttr('checked');
@ -648,8 +661,9 @@ var Privacy = (function () {
var status = ['active', 'default'];
for(var s in status) {
if(DataStore.getDB(Connection.desktop_hash, 'privacy-marker', status[s]) == list)
if(DataStore.getDB(Connection.desktop_hash, 'privacy-marker', status[s]) == list) {
$('#privacy .privacy-active input[name=' + status[s] + ']').attr('checked', true);
}
}
// Try to read the stored items
@ -660,10 +674,9 @@ var Privacy = (function () {
select.attr('disabled', true);
return self.get(list);
}
else
} else {
select.removeAttr('disabled');
}
// Parse the XML data!
$(items).find('item').each(function() {
@ -814,8 +827,9 @@ var Privacy = (function () {
$(type_check).attr('checked', true);
// Can apply a value?
if(value_input)
if(value_input) {
$(value_input).val(value);
}
// Apply the things to do
var privacy_do = '#privacy .privacy-third input[type="checkbox"]';
@ -924,8 +938,9 @@ var Privacy = (function () {
var list = $('#privacy .privacy-head .list-left select').val();
// No value?
if(!list)
if(!list) {
return false;
}
// Remove it from popup
$('#privacy .privacy-head .list-left select option[value="' + list + '"]').remove();
@ -941,8 +956,9 @@ var Privacy = (function () {
var status = ['active', 'default'];
for(var s in status) {
if(DataStore.getDB(Connection.desktop_hash, 'privacy-marker', status[s]) == list)
if(DataStore.getDB(Connection.desktop_hash, 'privacy-marker', status[s]) == list) {
self.change('', status[s]);
}
}
// Remove from server
@ -957,8 +973,9 @@ var Privacy = (function () {
$('#privacy .privacy-head .list-right input').keyup(function(e) {
// Not enter?
if(e.keyCode != 13)
if(e.keyCode != 13) {
return;
}
// Get list name
var list = $('#privacy .privacy-head .list-right input').val();
@ -1002,21 +1019,22 @@ var Privacy = (function () {
// Display the data!
self.displayForm(
item.attr('data-type'),
item.attr('data-value'),
item.attr('data-action'),
item.attr('data-order'),
item.attr('data-presence_in'),
item.attr('data-presence_out'),
item.attr('data-message'),
item.attr('data-iq')
);
item.attr('data-type'),
item.attr('data-value'),
item.attr('data-action'),
item.attr('data-order'),
item.attr('data-presence_in'),
item.attr('data-presence_out'),
item.attr('data-message'),
item.attr('data-iq')
);
});
$('#privacy .privacy-item a.item-add').click(function() {
// Cannot add anything?
if(!Common.exists('#privacy .privacy-head .list-left select option:selected'))
if(!Common.exists('#privacy .privacy-head .list-left select option:selected')) {
return false;
}
// Disable item select
$('#privacy .privacy-item select').attr('disabled', true);
@ -1034,8 +1052,9 @@ var Privacy = (function () {
$('#privacy .privacy-item a.item-remove').click(function() {
// Cannot add anything?
if(!Common.exists('#privacy .privacy-head .list-left select option:selected'))
if(!Common.exists('#privacy .privacy-head .list-left select option:selected')) {
return false;
}
// Get values
var list = $('#privacy .privacy-head .list-left select').val();
@ -1055,15 +1074,17 @@ var Privacy = (function () {
$('#privacy .privacy-head .list-left select option[value="' + list + '"]').remove();
// No more privacy lists?
if(!Common.exists('#privacy .privacy-head .list-left select option'))
if(!Common.exists('#privacy .privacy-head .list-left select option')) {
$('#privacy .privacy-head .list-left select').attr('disabled', true);
}
// Disable this list before removing it
var status = ['active', 'default'];
for(var s in status) {
if(DataStore.getDB(Connection.desktop_hash, 'privacy-marker', status[s]) == list)
if(DataStore.getDB(Connection.desktop_hash, 'privacy-marker', status[s]) == list) {
self.change('', status[s]);
}
}
}
@ -1079,14 +1100,16 @@ var Privacy = (function () {
$('#privacy .privacy-item a.item-save').click(function() {
// Canot push item?
if(Common.exists('#privacy .privacy-form input:disabled'))
if(Common.exists('#privacy .privacy-form input:disabled')) {
return false;
}
// Get the hash
var item_hash = '';
if(!$('#privacy .privacy-item select').is(':disabled'))
if(!$('#privacy .privacy-item select').is(':disabled')) {
item_hash = $('#privacy .privacy-item select option:selected').attr('data-hash');
}
// Read the form
var privacy_second = '#privacy .privacy-second';
@ -1142,17 +1165,17 @@ var Privacy = (function () {
// Push item to the server!
self.push(
item_list,
[item_type],
[item_value],
[item_action],
[item_order],
[item_prin],
[item_prout],
[item_msg],
[item_iq],
item_hash
);
item_list,
[item_type],
[item_value],
[item_action],
[item_order],
[item_prin],
[item_prout],
[item_msg],
[item_iq],
item_hash
);
return false;
});
@ -1170,16 +1193,19 @@ var Privacy = (function () {
var target = '#privacy .privacy-third input[type="checkbox"]';
// Must tick "everything" checkbox?
if(!$(target).filter(':checked').size())
if(!$(target).filter(':checked').size()) {
$(target + '[name="everything"]').attr('checked', true);
}
// Must untick the other checkboxes?
else if($(this).is('[name="everything"]'))
else if($(this).is('[name="everything"]')) {
$(target + ':not([name="everything"])').removeAttr('checked');
}
// Must untick "everything" checkbox?
else
else {
$(target + '[name="everything"]').removeAttr('checked');
}
});
$('#privacy .privacy-active input[name="order"]').keyup(function() {
@ -1187,14 +1213,16 @@ var Privacy = (function () {
var value = $(this).val();
// No value?
if(!value)
if(!value) {
return;
}
// Not a number?
if(isNaN(value))
if(isNaN(value)) {
value = 1;
else
} else {
value = parseInt(value);
}
// Negative?
if(value < 0)
@ -1206,8 +1234,9 @@ var Privacy = (function () {
.blur(function() {
// No value?
if(!$(this).val())
if(!$(this).val()) {
$(this).val('1');
}
});
$('#privacy .privacy-active .privacy-active-elements input').change(function() {
@ -1216,14 +1245,16 @@ var Privacy = (function () {
var state_name = $(this).attr('name');
// Cannot continue?
if(!list_name || !state_name)
if(!list_name || !state_name) {
return;
}
// Change the current list status
if($(this).filter(':checked').size())
if($(this).filter(':checked').size()) {
self.change(list_name, state_name);
else
} else {
self.change('', state_name);
}
});
} catch(e) {
Console.error('Privacy.instance', e);

View file

@ -108,8 +108,9 @@ var Receipts = (function () {
aMsg.setID(id);
// Any type?
if(type)
if(type) {
aMsg.setType(type);
}
// Append the received node
aMsg.appendNode('received', {'xmlns': NS_URN_RECEIPTS, 'id': id});
@ -147,7 +148,7 @@ var Receipts = (function () {
// Remove the group marker
if(!group.find('.one-line[data-lost]').size()) {
group.find('b.name').removeClass('talk-images')
.removeAttr('title');
.removeAttr('title');
}
} catch(e) {
Console.error('Receipts.messageReceived', e);
@ -170,14 +171,19 @@ var Receipts = (function () {
try {
// Fire a check 10 seconds later
$('#' + hash + ' .one-line[data-id="' + id + '"]').oneTime('10s', function() {
var this_sel = $(this);
// Not received?
if($(this).attr('data-received') != 'true') {
if(this_sel.attr('data-received') != 'true') {
// Add a "lost" marker
$(this).attr('data-lost', 'true');
this_sel.attr('data-lost', 'true');
// Add a warn on the buddy-name
$(this).parent().find('b.name').addClass('talk-images')
.attr('title', Common._e("Your friend seems not to have received your message(s)!"));
this_sel.parent().find('b.name').addClass('talk-images')
.attr(
'title',
Common._e("Your friend seems not to have received your message(s)!")
);
}
});
} catch(e) {

View file

@ -57,12 +57,12 @@ var Roster = (function () {
// Parse the roster xml
$(iq.getQuery()).find('item').each(function() {
// Get user data
var _this = $(this);
var user_xid = _this.attr('jid');
var user_subscription = _this.attr('subscription');
var this_sel = $(this);
var user_xid = this_sel.attr('jid');
var user_subscription = this_sel.attr('subscription');
// Parse roster data & display user
self.parse($(this), 'load');
self.parse(this_sel, 'load');
// Request user microblog (populates channel)
if(user_xid && ((user_subscription == 'both') || (user_subscription == 'to'))) {
@ -106,17 +106,20 @@ var Roster = (function () {
current.find('group').each(function() {
var group_text = $(this).text();
if(group_text)
if(group_text) {
groups.push(group_text);
}
});
// No group?
if(!groups.length)
if(!groups.length) {
groups.push(Common._e("Unclassified"));
}
// If no name is defined, we get the default nick of the buddy
if(!dName)
if(!dName) {
dName = Common.getXIDNick(xid);
}
self.display(xid, xidHash, dName, subscription, groups, mode);
} catch(e) {
@ -135,23 +138,28 @@ var Roster = (function () {
try {
$('#roster .one-group').each(function() {
var this_sel = $(this);
// Current values
var check = $(this).find('.buddy').size();
var hidden = $(this).find('.buddy:not(.hidden-buddy:hidden)').size();
var check = this_sel.find('.buddy').size();
var hidden = this_sel.find('.buddy:not(.hidden-buddy:hidden)').size();
// Special case: the filtering tool
if(Search.search_filtered)
hidden = $(this).find('.buddy:visible').size();
if(Search.search_filtered) {
hidden = this_sel.find('.buddy:visible').size();
}
// If the group is empty
if(!check)
$(this).remove();
if(!check) {
this_sel.remove();
}
// If the group contains no online buddy (and is not just hidden)
if(!hidden && $(this).find('a.group').hasClass('minus'))
$(this).hide();
else
$(this).show();
if(!hidden && this_sel.find('a.group').hasClass('minus')) {
this_sel.hide();
} else {
this_sel.show();
}
});
} catch(e) {
Console.error('Roster.updateGroups', e);
@ -202,8 +210,9 @@ var Roster = (function () {
var privacy_class = '';
var privacy_state = Privacy.status('block', dXID);
if(privacy_state == 'deny')
if(privacy_state == 'deny') {
privacy_class = ' blocked';
}
// For each group this buddy has
$.each(dGroup, function(i, cGroup) {
@ -214,8 +223,9 @@ var Roster = (function () {
var groupBuddies = groupContent + ' .group-buddies';
// Is this group blocked?
if((Privacy.status('block', cGroup) == 'deny') && (privacy_state != 'allow'))
if((Privacy.status('block', cGroup) == 'deny') && (privacy_state != 'allow')) {
privacy_class = ' blocked';
}
// Group not yet displayed
if(!Common.exists(groupContent)) {
@ -272,13 +282,13 @@ var Roster = (function () {
html += '<div class="name">';
// Special gateway code
if(is_gateway)
if(is_gateway) {
html += presence_code +
name_code;
else
} else {
html += name_code +
presence_code;
}
html += '</div></div></div>';
@ -374,8 +384,9 @@ var Roster = (function () {
});
// Create a new checked checkbox
if(!group_exists)
if(!group_exists) {
$(bm_choose).prepend('<label><input type="checkbox" data-group="' + escaped_value + '" /><span>' + this_value.htmlEnc() + '</span></label>');
}
// Check the checkbox
$(bm_choose + ' input[data-group="' + escaped_value + '"]').attr('checked', true);
@ -423,8 +434,9 @@ var Roster = (function () {
Bubble.close();
// First unregister if gateway
if(Common.isGateway(xid))
if(Common.isGateway(xid)) {
self.unregisterGateway(xid);
}
// Then send roster removal query
self.send(xid, 'remove');
@ -462,8 +474,9 @@ var Roster = (function () {
// If the pointer is on a stored presence
if(current.match(db_regex)) {
if(Common.bareXID(RegExp.$1) == xid)
if(Common.bareXID(RegExp.$1) == xid) {
DataStore.storageDB.removeItem(current);
}
}
}
@ -510,13 +523,15 @@ var Roster = (function () {
// Apply the hover event
$(bPath).hover(function() {
// Another bubble exist
if(Common.exists('#roster .buddy-infos'))
if(Common.exists('#roster .buddy-infos')) {
return false;
}
$(bPath).oneTime(200, function() {
// Another bubble exist
if(Common.exists('#roster .buddy-infos'))
if(Common.exists('#roster .buddy-infos')) {
return false;
}
// Add this bubble!
Bubble.show(iPath);
@ -552,36 +567,45 @@ var Roster = (function () {
// Click events
$(bPath + ' .bi-view a').click(function() {
var this_sel = $(this);
// Renitialize the buddy infos
Bubble.close();
// Profile
if($(this).is('.profile'))
if(this_sel.is('.profile')) {
UserInfos.open(xid);
}
// Channel
else if($(this).is('.channel'))
else if(this_sel.is('.channel')) {
Microblog.fromInfos(xid, hash);
}
// Command
else if($(this).is('.commands'))
else if(this_sel.is('.commands')) {
AdHoc.retrieve(xid);
}
return false;
});
// Jingle events
$(bPath + ' .bi-jingle a').click(function() {
var this_sel = $(this);
// Renitialize the buddy infos
Bubble.close();
// Audio call?
if($(this).is('.audio'))
if(this_sel.is('.audio')) {
Jingle.start(xid, 'audio');
}
// Video call?
else if($(this).is('.video'))
else if(this_sel.is('.video')) {
Jingle.start(xid, 'video');
}
return false;
});
@ -593,8 +617,9 @@ var Roster = (function () {
});
});
}, function() {
if(!Common.exists(iPath + ' .manage-infos'))
if(!Common.exists(iPath + ' .manage-infos')) {
Bubble.close();
}
$(bPath).stopTime();
});
@ -623,8 +648,9 @@ var Roster = (function () {
// Get the offset to define
var offset = 3;
if(Common.isGateway(xid))
if(Common.isGateway(xid)) {
offset = -8;
}
// Process the position
var v_position = $(buddy).position().top + offset;
@ -634,10 +660,11 @@ var Roster = (function () {
$(buddy_infos).css('top', v_position);
// Apply the left/right position
if($('html').attr('dir') == 'rtl')
if($('html').attr('dir') == 'rtl') {
$(buddy_infos).css('right', h_position);
else
} else {
$(buddy_infos).css('left', h_position);
}
} catch(e) {
Console.error('Roster.buddyInfosPosition', e);
}
@ -659,14 +686,17 @@ var Roster = (function () {
// Each checked checkboxes
$(path + 'div.bm-choose input[type="checkbox"]').filter(':checked').each(function() {
array.push(unescape($(this).attr('data-group')));
array.push(
unescape($(this).attr('data-group'))
);
});
// Entered input value (and not yet in the array)
var value = $.trim($(path + 'p.bm-group input').val());
if(value && !Utils.existArrayValue(array, value))
if(value && !Utils.existArrayValue(array, value)) {
array.push(value);
}
return array;
} catch(e) {
@ -719,10 +749,13 @@ var Roster = (function () {
var groups = [];
$('#roster .one-group').each(function() {
var current = unescape($(this).attr('data-group'));
var current = unescape(
$(this).attr('data-group')
);
if((current != Common._e("Unclassified")) && (current != Common._e("Gateways")))
if((current != Common._e("Unclassified")) && (current != Common._e("Gateways"))) {
groups.push(current);
}
});
return groups.sort();
@ -757,8 +790,9 @@ var Roster = (function () {
// Get the group privacy state
for(var g in groups) {
if((Privacy.status('block', groups[g]) == 'deny') && (privacy_state != 'allow'))
if((Privacy.status('block', groups[g]) == 'deny') && (privacy_state != 'allow')) {
privacy_state = 'deny';
}
}
// The subscription with this buddy is not full
@ -767,21 +801,24 @@ var Roster = (function () {
html += '<p class="bm-authorize talk-images">';
// Link to allow to see our status
if((subscription == 'to') || (subscription == 'none'))
if((subscription == 'to') || (subscription == 'none')) {
authorize_links += '<a href="#" class="to">' + Common._e("Authorize") + '</a>';
}
// Link to ask to see his/her status
if((subscription == 'from') || (subscription == 'none')) {
if(authorize_links)
if(authorize_links) {
authorize_links += ' / ';
}
authorize_links += '<a href="#" class="from">' + Common._e("Ask for authorization") + '</a>';
}
// Link to unblock this buddy
if((privacy_state == 'deny') && privacy_active) {
if(authorize_links)
if(authorize_links) {
authorize_links += ' / ';
}
html += '<a href="#" class="unblock">' + Common._e("Unblock") + '</a>';
}
@ -795,13 +832,15 @@ var Roster = (function () {
remove_links = '<a href="#" class="remove">' + Common._e("Remove") + '</a>';
// This buddy is allowed to see our presence, we can show a "prohibit" link
if((subscription == 'both') || (subscription == 'from'))
if((subscription == 'both') || (subscription == 'from')) {
remove_links += ' / <a href="#" class="prohibit">' + Common._e("Prohibit") + '</a>';
}
// Complete the HTML code
if((privacy_state != 'deny') && privacy_active) {
if(remove_links)
if(remove_links) {
remove_links += ' / ';
}
remove_links += '<a href="#" class="block">' + Common._e("Block") + '</a>';
}
@ -812,11 +851,12 @@ var Roster = (function () {
'<p class="bm-rename talk-images"><label>' + Common._e("Rename") + '</label> <input type="text" value="' + Common.encodeQuotes(nick) + '" /></p>';
// Only show group tool if not a gateway
if(!Common.isGateway(xid))
if(!Common.isGateway(xid)) {
html += '<p class="bm-group talk-images"><label>' + Common._e("Groups") + '</label> <input type="text" /></p>' +
'<div class="bm-choose">' +
'<div></div>' +
'</div>';
}
// Close the DOM element
html += '<a href="#" class="save">' + Common._e("Save") + '</a>' +
@ -836,8 +876,9 @@ var Roster = (function () {
// Is the current group checked?
var checked = '';
if(Utils.existArrayValue(groups, all_groups_current))
if(Utils.existArrayValue(groups, all_groups_current)) {
checked = ' checked="true"';
}
// Add the current group HTML
all_groups_dom += '<label><input type="checkbox" data-group="' + escape(all_groups_current) + '"' + checked + ' /><span>' + all_groups_current.htmlEnc() + '</span></label>';
@ -901,17 +942,20 @@ var Roster = (function () {
var item = iqQuery.appendChild(iq.buildNode('item', {'xmlns': NS_ROSTER, 'jid': xid}));
// Any subscription?
if(subscription)
if(subscription) {
item.setAttribute('subscription', subscription);
}
// Any name?
if(name)
if(name) {
item.setAttribute('name', name);
}
// Any group?
if(group && group.length) {
for(var i in group)
for(var i in group) {
item.appendChild(iq.buildNode('group', {'xmlns': NS_ROSTER}, group[i]));
}
}
con.send(iq);
@ -936,8 +980,9 @@ var Roster = (function () {
var new_height = $('#left-content').height() - $('#my-infos').height() - 97;
// New height too small
if(new_height < 211)
if(new_height < 211) {
new_height = 211;
}
// Apply the new height
$('#roster .content').css('height', new_height);
@ -1034,10 +1079,11 @@ var Roster = (function () {
.blur(function() {
// Nothing is entered, put the placeholder instead
if(!$.trim($(this).val()))
if(!$.trim($(this).val())) {
aFilter.hide();
else
} else {
aFilter.show();
}
})
.keyup(function(e) {
@ -1062,8 +1108,9 @@ var Roster = (function () {
// When the user click on the add button, show the contact adding tool
$('#roster .foot .add').click(function() {
// Yet displayed?
if(Common.exists('#buddy-conf-add'))
if(Common.exists('#buddy-conf-add')) {
return Bubble.close();
}
// Add the bubble
Bubble.show('#buddy-conf-add');
@ -1137,25 +1184,28 @@ var Roster = (function () {
var gateway = unescape($('.add-contact-gateway').val());
// Generate the XID to add
if((gateway != 'none') && xid)
if((gateway != 'none') && xid) {
xid = xid.replace(/@/g, '%') + '@' + gateway;
else
} else {
xid = Common.generateXID(xid, 'chat');
}
// Submit the form
if(xid && Common.getXIDNick(xid) && (xid != Common.getXID()))
if(xid && Common.getXIDNick(xid) && (xid != Common.getXID())) {
self.addThisContact(xid, name);
else
} else {
$(document).oneTime(10, function() {
$('.add-contact-jid').addClass('please-complete').focus();
});
}
return false;
}
// Escape : quit
if(e.keyCode == 27)
if(e.keyCode == 27) {
Bubble.close();
}
});
// Click event on search link
@ -1175,8 +1225,9 @@ var Roster = (function () {
// When the user click on the join button, show the chat joining tool
$('#roster .foot .join').click(function() {
// Yet displayed?
if(Common.exists('#buddy-conf-join'))
if(Common.exists('#buddy-conf-join')) {
return Bubble.close();
}
// Add the bubble
Bubble.show('#buddy-conf-join');
@ -1209,10 +1260,7 @@ var Roster = (function () {
// Select something from the search
if(Common.exists(dHovered)) {
Search.addBuddy(destination, $(dHovered).attr('data-xid'));
}
// Join something
else {
} else {
var xid = $.trim($('.join-jid').val());
var type = $('.buddy-conf-join-select').val();
@ -1228,14 +1276,10 @@ var Roster = (function () {
// Create a new chat
Chat.checkCreate(xid, type);
}
else {
} else {
$('.join-jid').addClass('please-complete');
}
}
else {
} else {
$('.join-jid').addClass('please-complete');
}
}
@ -1250,8 +1294,9 @@ var Roster = (function () {
// Buddy search?
else if($('.buddy-conf-join-select').val() == 'chat') {
// New buddy search
if((e.keyCode != 40) && (e.keyCode != 38))
if((e.keyCode != 40) && (e.keyCode != 38)) {
Search.createBuddy(destination);
}
// Navigating with keyboard in the results
Search.arrowsBuddy(e, destination);
@ -1282,8 +1327,9 @@ var Roster = (function () {
// When the user click on the groupchat button, show the groupchat menu
$('#roster .foot .groupchat').click(function() {
// Yet displayed?
if(Common.exists('#buddy-conf-groupchat'))
if(Common.exists('#buddy-conf-groupchat')) {
return Bubble.close();
}
// Add the bubble
Bubble.show('#buddy-conf-groupchat');
@ -1334,12 +1380,61 @@ var Roster = (function () {
return false;
});
// When the user click on the muji button, show the muji menu
$('#roster .foot .muji').click(function() {
// Yet displayed?
if(Common.exists('#buddy-conf-muji') || Call.is_ongoing()) {
return Bubble.close();
}
// Add the bubble
Bubble.show('#buddy-conf-muji');
// Append the content
$('#roster .roster-muji').append(
'<div id="buddy-conf-muji" class="buddy-conf-item bubble removable">' +
'<div class="buddy-conf-subarrow talk-images"></div>' +
'<div class="buddy-conf-subitem">' +
'<p class="buddy-conf-p">' + Common._e("Launch a group call") + '</p>' +
'<p class="buddy-conf-text">' +
'- <a href="#" class="buddy-conf-muji-conference" data-media="audio">' + Common._e("Audio conference") + '</a>' +
'</p>' +
'<p class="buddy-conf-text">' +
'- <a href="#" class="buddy-conf-muji-conference" data-media="video">' + Common._e("Video conference") + '</a>' +
'</p>' +
'</div>' +
'</div>'
);
// When the user wants to launch
$('.buddy-conf-muji-conference').click(function() {
var media = $(this).attr('data-media');
var room_name = hex_md5(media + DateUtils.getTimeStamp() + Math.random());
var room = Common.generateXID(room_name, 'groupchat');
if(media && room && room_name) {
Muji.start(room, media);
}
Bubble.close();
return false;
});
return false;
});
// When the user click on the more button, show the more menu
$('#roster .foot .more').click(function() {
// Yet displayed?
if(Common.exists('#buddy-conf-more'))
if(Common.exists('#buddy-conf-more')) {
return Bubble.close();
}
// Add the bubble
Bubble.show('#buddy-conf-more');
@ -1410,11 +1505,13 @@ var Roster = (function () {
$('.buddy-conf-more-display-available').show();
}
if(Features.enabledCommands())
if(Features.enabledCommands()) {
$('.buddy-conf-more-commands').parent().show();
}
if(DataStore.getDB(Connection.desktop_hash, 'privacy-marker', 'available'))
if(DataStore.getDB(Connection.desktop_hash, 'privacy-marker', 'available')) {
$('.buddy-conf-more-privacy').parent().show();
}
return false;
});

View file

@ -97,34 +97,44 @@ var RosterX = (function () {
// Parse data
x.find('item').each(function() {
var this_sel = $(this);
// Generate group XML
var group = '';
$(this).find('group').each(function() {
group += '<group>' + $(this).text().htmlEnc() + '</group>';
this_sel.find('group').each(function() {
group += '<group>' + this_sel.text().htmlEnc() + '</group>';
});
if(group)
if(group) {
group = '<groups>' + group + '</groups>';
}
// Display it!
self.display($(this).attr('jid'), $(this).attr('name'), group, $(this).attr('action'));
self.display(
this_sel.attr('jid'),
this_sel.attr('name'),
group,
this_sel.attr('action')
);
});
// Click to check/uncheck
$('#rosterx .oneresult').click(function(evt) {
// No need to apply when click on input
if($(evt.target).is('input[type="checkbox"]'))
if($(evt.target).is('input[type="checkbox"]')) {
return;
}
// Input selector
var checkbox = $(this).find('input[type="checkbox"]');
// Check or uncheck?
if(checkbox.filter(':checked').size())
if(checkbox.filter(':checked').size()) {
checkbox.removeAttr('checked');
else
} else {
checkbox.attr('checked', true);
}
});
} catch(e) {
Console.error('RosterX.parse', e);
@ -146,16 +156,19 @@ var RosterX = (function () {
try {
// End if no XID
if(!xid)
if(!xid) {
return false;
}
// Set up a default action if no one
if(!action || (action != 'modify') || (action != 'delete'))
if(!action || (action != 'modify') || (action != 'delete')) {
action = 'add';
}
// Override "undefined" for nickname
if(!nick)
if(!nick) {
nick = '';
}
// Display it
$('#rosterx .results').append(
@ -178,25 +191,27 @@ var RosterX = (function () {
/**
* Saves the rosterx settings
* @public
* @return {undefined}
* @return {boolean}
*/
self.save = function() {
try {
// Send the requests
$('#rosterx .results input[type="checkbox"]').filter(':checked').each(function() {
var this_sel = $(this);
// Read the attributes
var nick = $(this).attr('data-name');
var xid = $(this).attr('data-xid');
var action = $(this).attr('data-action');
var group = $(this).attr('data-group');
var nick = this_sel.attr('data-name');
var xid = this_sel.attr('data-xid');
var action = this_sel.attr('data-action');
var group = this_sel.attr('data-group');
// Parse groups XML
var group_arr = [];
if(group) {
$(group).find('group').each(function() {
group_arr.push($(this).text().revertHtmlEnc());
group_arr.push(this_sel.text().revertHtmlEnc());
});
}
@ -233,6 +248,8 @@ var RosterX = (function () {
self.close();
} catch(e) {
Console.error('RosterX.save', e);
} finally {
return false;
}
};
@ -248,17 +265,25 @@ var RosterX = (function () {
try {
// Click events
$('#rosterx .bottom .finish').click(function() {
if($(this).is('.save'))
var this_sel = $(this);
if(this_sel.is('.save')) {
return self.save();
if($(this).is('.cancel'))
}
if(this_sel.is('.cancel')) {
return self.close();
}
});
$('#rosterx .rosterx-head a').click(function() {
if($(this).is('.check'))
var this_sel = $(this);
if(this_sel.is('.check')) {
$('#rosterx .results input[type="checkbox"]').attr('checked', true);
else if($(this).is('.uncheck'))
} else if(this_sel.is('.uncheck')) {
$('#rosterx .results input[type="checkbox"]').removeAttr('checked');
}
return false;
});

View file

@ -112,8 +112,9 @@ var Search = (function () {
// Get the old value (if there's another value)
var old = '';
if(value.match(/(^(.+)(,)(\s)?)(\w+)$/))
if(value.match(/(^(.+)(,)(\s)?)(\w+)$/)) {
old = RegExp.$1;
}
// Add the XID to the "to" input and focus on it
$(document).oneTime(10, function() {
@ -144,8 +145,9 @@ var Search = (function () {
var value = $(destination + ' input').val();
// Separation with a comma?
if(value.match(/^(.+)((,)(\s)?)(\w+)$/))
if(value.match(/^(.+)((,)(\s)?)(\w+)$/)) {
value = RegExp.$5;
}
// Get the result array
var entered = self.processBuddy(value);
@ -217,8 +219,9 @@ var Search = (function () {
var code = evt.keyCode;
// Not the key we want here
if((code != 40) && (code != 38))
if((code != 40) && (code != 38)) {
return;
}
// Remove the eventual mouse hover marker
$(destination + ' ul').removeAttr('mouse-hover');
@ -234,25 +237,25 @@ var Search = (function () {
if(Common.exists(path + '.hovered')) {
var index = $(path).attr('data-hovered');
if(index)
if(index) {
i = parseInt(index);
}
if(code == 40)
if(code == 40) {
i++;
else
} else {
i--;
}
} else if(code == 38) {
i = pSize - 1;
}
else if(code == 38)
i = pSize - 1;
// We must not override the maximum i limit
if(i >= pSize)
if(i >= pSize) {
i = 0;
// We must not have negative i
else if(i < 0)
} else if(i < 0) {
i = pSize - 1;
}
// Modify the list
$(path + '.hovered').removeClass('hovered');
@ -289,11 +292,13 @@ var Search = (function () {
// Only show the buddies which match the search
if(!Roster.blist_all) {
for(var i in rFilter)
for(var i in rFilter) {
$('#roster .buddy[data-xid="' + escape(rFilter[i]) + '"]:not(.hidden-buddy)').show();
}
} else {
for(var j in rFilter)
for(var j in rFilter) {
$('#roster .buddy[data-xid="' + escape(rFilter[j]) + '"]').show();
}
}
} catch(e) {
Console.error('Search.goFilterBuddy', e);
@ -317,8 +322,9 @@ var Search = (function () {
$('#roster .buddy').show();
// Only show available buddies
if(!Roster.blist_all)
if(!Roster.blist_all) {
$('#roster .buddy.hidden-buddy').hide();
}
// Update the groups
Roster.updateGroups();
@ -349,15 +355,13 @@ var Search = (function () {
// Nothing is entered, or escape pressed
if(!value || (keycode == 27)) {
if(keycode == 27)
if(keycode == 27) {
input.val('');
}
self.resetFilterBuddy();
cancel.hide();
}
// Process the filtering
else {
} else {
cancel.show();
self.goFilterBuddy(value);
}

View file

@ -20,6 +20,51 @@ var Smileys = (function () {
var self = {};
/* Constants */
self.emote_list = {
'biggrin': ':-D',
'devil': ']:->',
'coolglasses': '8-)',
'tongue': ':-P',
'smile': ':-)',
'wink': ';-)',
'blush': ':-$',
'stare': ':-|',
'frowning': ':-/',
'oh': '=-O',
'unhappy': ':-(',
'cry': ':\'-(',
'angry': ':-@',
'puke': ':-!',
'hugright': '({)',
'hugleft': '(})',
'lion': ':3',
'pussy': '(@)',
'bat': ':-[',
'kiss': ':-{}',
'heart': '<3',
'brheart': '</3',
'flower': '@}->--',
'brflower': '(W)',
'thumbup': '(Y)',
'thumbdown': '(N)',
'lamp': '(I)',
'coffee': '(C)',
'drink': '(D)',
'beer': '(B)',
'boy': '(Z)',
'girl': '(X)',
'photo': '(P)',
'phone': '(T)',
'music': '(8)',
'cuffs': '(%)',
'mail': '(E)',
'rainbow': '(R)',
'star': '(*)',
'moon': '(S)'
};
/**
* Generates the correct HTML code for an emoticon insertion tool
* @public
@ -43,101 +88,19 @@ var Smileys = (function () {
* Emoticon links arrays
* @public
* @param {string} hash
* @return {object}
* @return {string}
*/
self.links = function(hash) {
try {
var links = '';
var sArray = [
':-D',
']:->',
'8-)',
':-P',
':-)',
';-)',
':-$',
':-|',
':-/',
'=-O',
':-(',
':\'-(',
':-@',
':-!',
'({)',
'(})',
':3',
'(@)',
':-[',
':-{}',
'<3',
'</3',
'@}->--',
'(W)',
'(Y)',
'(N)',
'(I)',
'(C)',
'(D)',
'(B)',
'(Z)',
'(X)',
'(P)',
'(T)',
'(8)',
'(%)',
'(E)',
'(R)',
'(*)',
'(S)'
];
var cArray = [
'biggrin',
'devil',
'coolglasses',
'tongue',
'smile',
'wink',
'blush',
'stare',
'frowning',
'oh',
'unhappy',
'cry',
'angry',
'puke',
'hugright',
'hugleft',
'lion',
'pussy',
'bat',
'kiss',
'heart',
'brheart',
'flower',
'brflower',
'thumbup',
'thumbdown',
'lamp',
'coffee',
'drink',
'beer',
'boy',
'girl',
'photo',
'phone',
'music',
'cuffs',
'mail',
'rainbow',
'star',
'moon'
];
for(var i in sArray) {
links += self.emoteLink(sArray[i], cArray[i], hash);
for(var cur_emote in self.emote_list) {
links += self.emoteLink(
self.emote_list[cur_emote],
cur_emote,
hash
);
}
return links;

View file

@ -70,44 +70,51 @@ var Storage = (function () {
// Parse the options xml
options.find('option').each(function() {
var this_sel = $(this);
// We retrieve the informations
var type = $(this).attr('type');
var value = $(this).text();
var type = this_sel.attr('type');
var value = this_sel.text();
// We display the storage
DataStore.setDB(Connection.desktop_hash, 'options', type, value);
// If this is the buddy list show status
if((type == 'roster-showall') && (value == '1'))
if((type == 'roster-showall') && (value == '1')) {
Interface.showAllBuddies('storage');
}
});
// Parse the inbox xml
inbox.find('message').each(function() {
var this_sel = $(this);
Inbox.storeMessage(
$(this).attr('from'),
$(this).attr('subject'),
$(this).text(),
$(this).attr('status'),
$(this).attr('id'),
$(this).attr('date'),
[
$(this).attr('file_title'),
$(this).attr('file_href'),
$(this).attr('file_type'),
$(this).attr('file_length')
]
);
this_sel.attr('from'),
this_sel.attr('subject'),
this_sel.text(),
this_sel.attr('status'),
this_sel.attr('id'),
this_sel.attr('date'),
[
this_sel.attr('file_title'),
this_sel.attr('file_href'),
this_sel.attr('file_type'),
this_sel.attr('file_length')
]
);
});
// Parse the bookmarks xml
bookmarks.find('conference').each(function() {
var this_sel = $(this);
// We retrieve the informations
var xid = $(this).attr('jid');
var name = $(this).attr('name');
var autojoin = $(this).attr('autojoin');
var password = $(this).find('password').text();
var nick = $(this).find('nick').text();
var xid = this_sel.attr('jid');
var name = this_sel.attr('name');
var autojoin = this_sel.attr('autojoin');
var password = this_sel.find('password').text();
var nick = this_sel.find('nick').text();
// Filter autojoin (compatibility)
autojoin = ((autojoin == 'true') || (autojoin == '1')) ? 'true' : 'false';
@ -116,13 +123,21 @@ var Storage = (function () {
Favorites.display(xid, name, nick, autojoin, password);
// Join the chat if autojoin is enabled
if(autojoin == 'true')
if(autojoin == 'true') {
Chat.checkCreate(xid, 'groupchat', nick, password, name);
}
});
// Parse the roster notes xml
rosternotes.find('note').each(function() {
DataStore.setDB(Connection.desktop_hash, 'rosternotes', $(this).attr('jid'), $(this).text());
var this_sel = $(this);
DataStore.setDB(
Connection.desktop_hash,
'rosternotes',
this_sel.attr('jid'),
this_sel.text()
);
});
// Options received

View file

@ -31,14 +31,18 @@ var System = (function () {
var url = window.location.href;
// If the URL has variables, remove them
if(url.indexOf('?') != -1)
if(url.indexOf('?') != -1) {
url = url.split('?')[0];
if(url.indexOf('#') != -1)
}
if(url.indexOf('#') != -1) {
url = url.split('#')[0];
}
// No "/" at the end
if(!url.match(/(.+)\/$/))
if(!url.match(/(.+)\/$/)) {
url += '/';
}
return url;
} catch(e) {

View file

@ -51,8 +51,9 @@ var Talk = (function () {
try {
// Talkpage exists?
if(Common.exists('#talk'))
if(Common.exists('#talk')) {
return false;
}
// Anonymous detector
var anonymous = Utils.isAnonymous();
@ -116,14 +117,14 @@ var Talk = (function () {
if(!anonymous) html +=
'<div class="tools-all">' +
'<div class="tools jingle talk-images" onclick="return Jingle.open();">' +
'<div class="tools call talk-images" onclick="return Call.open();">' +
'<span class="streaming-items">' +
'<span class="counter" data-default="00:00:00">00:00:00</span>' +
'<a class="stop" href="#" onclick="return Jingle.stop();">' + Common._e("Stop") + '</a>' +
'<a class="stop" href="#" onclick="return Call.stop();">' + Common._e("Stop") + '</a>' +
'</span>' +
'</div>' +
'<div class="jingle-content tools-content">' +
'<div class="call-content tools-content">' +
'<div class="tools-content-subarrow talk-images"></div>' +
'<div class="tools-content-subitem"></div>' +
@ -157,6 +158,10 @@ var Talk = (function () {
'<a href="#" class="groupchat talk-images" title="' + Common._e("Your groupchats") + '"></a>' +
'</div>' +
'<div class="roster-muji roster-icon muji-hidable">' +
'<a href="#" class="muji talk-images" title="' + Common._e("Audio/video conference") + '"></a>' +
'</div>' +
'<div class="roster-more roster-icon">' +
'<a href="#" class="more talk-images" title="' + Common._e("More stuff") + '"></a>' +
'</div>' +

View file

@ -37,8 +37,9 @@ var Tooltip = (function () {
var path_bubble = path_tooltip + ' .bubble-' + type;
// Yet exists?
if(Common.exists(path_bubble))
if(Common.exists(path_bubble)) {
return false;
}
// Generates special tooltip HTML code
var title = '';
@ -211,47 +212,52 @@ var Tooltip = (function () {
// Click event on style bubble
$(bubble_style).click(function() {
// Hide font selector if opened
if($(font_list).is(':visible'))
if($(font_list).is(':visible')) {
$(font_current).click();
}
// Hide font-size selector if opened
if($(fontsize_list).is(':visible'))
if($(fontsize_list).is(':visible')) {
$(fontsize_current).click();
}
// Hide color selector if opened
if($(color_hex).is(':visible'))
if($(color_hex).is(':visible')) {
$(color_more).click();
}
});
// Click event on font picker
$(font_current).click(function() {
var this_sel = $(this);
// The clicked color is yet selected
if($(font_list).is(':visible'))
$(this).parent().removeClass('listed');
else
$(this).parent().addClass('listed');
if($(font_list).is(':visible')) {
this_sel.parent().removeClass('listed');
} else {
this_sel.parent().addClass('listed');
}
return false;
});
// Click event on a new font in the picker
$(font_select).click(function() {
var this_sel = $(this);
// No font selected
if(!$(this).attr('data-value')) {
if(!this_sel.attr('data-value')) {
$(font_current).removeAttr('data-font')
.removeAttr('data-value')
.text(Common._e("None"));
$(message_area).removeAttr('data-font');
}
// A font is defined
else {
$(font_current).attr('data-font', $(this).attr('data-font'))
.attr('data-value', $(this).attr('data-value'))
.text($(font_list).find('a[data-value="' + $(this).attr('data-value') + '"]').text());
} else {
$(font_current).attr('data-font', this_sel.attr('data-font'))
.attr('data-value', this_sel.attr('data-value'))
.text($(font_list).find('a[data-value="' + this_sel.attr('data-value') + '"]').text());
$(message_area).attr('data-font', $(this).attr('data-value'));
$(message_area).attr('data-font', this_sel.attr('data-value'));
}
return false;
@ -259,28 +265,33 @@ var Tooltip = (function () {
// Click event on font-size picker
$(fontsize_current).click(function() {
var this_sel = $(this);
// The clicked color is yet selected
if($(fontsize_list).is(':visible'))
$(this).parent().removeClass('listed');
else
$(this).parent().addClass('listed');
if($(fontsize_list).is(':visible')) {
this_sel.parent().removeClass('listed');
} else {
this_sel.parent().addClass('listed');
}
return false;
});
// Click event on a new font-size in the picker
$(fontsize_select).click(function() {
var this_sel = $(this);
// No font-size selected
if(!$(this).attr('data-value')) {
if(!this_sel.attr('data-value')) {
$(fontsize_current).removeAttr('data-value').text(Common._e("16"));
$(message_area).removeAttr('data-fontsize');
}
// A font-size is defined
else {
$(fontsize_current).attr('data-value', $(this).attr('data-value'))
.text($(this).attr('data-value'));
$(message_area).attr('data-fontsize', $(this).attr('data-value'));
$(fontsize_current).attr('data-value', this_sel.attr('data-value'))
.text(this_sel.attr('data-value'));
$(message_area).attr('data-fontsize', this_sel.attr('data-value'));
}
return false;
@ -288,19 +299,21 @@ var Tooltip = (function () {
// Click event on color picker
$(colors).click(function() {
var this_sel = $(this);
// Reset the manual picker
$(color_hex).find('input').val('');
// The clicked color is yet selected
if($(this).hasClass('selected')) {
if(this_sel.hasClass('selected')) {
$(message_area).removeAttr('data-color');
$(this).removeClass('selected');
this_sel.removeClass('selected');
}
else {
$(message_area).attr('data-color', $(this).attr('data-color'));
$(message_area).attr('data-color', this_sel.attr('data-color'));
$(colors).removeClass('selected');
$(this).addClass('selected');
this_sel.addClass('selected');
}
return false;
@ -308,12 +321,13 @@ var Tooltip = (function () {
// Click event on color picker
$(color_more).click(function() {
var this_sel = $(this);
// The clicked color is yet selected
if($(color_hex).is(':visible'))
$(this).parent().removeClass('opened');
else {
$(this).parent().addClass('opened');
if($(color_hex).is(':visible')) {
this_sel.parent().removeClass('opened');
} else {
this_sel.parent().addClass('opened');
// Focus
$(document).oneTime(10, function() {
@ -331,6 +345,8 @@ var Tooltip = (function () {
// Keyup event on color picker
$(color_hex).find('input').keyup(function(e) {
var this_sel = $(this);
// Submit
if(e.keyCode == 13) {
if($(color_hex).is(':visible')) {
@ -350,32 +366,37 @@ var Tooltip = (function () {
$(colors).removeClass('selected');
// Change value
var new_value = $(this).val().replace(/([^a-z0-9]+)/gi, '');
$(this).val(new_value);
var new_value = this_sel.val().replace(/([^a-z0-9]+)/gi, '');
this_sel.val(new_value);
if(new_value)
if(new_value) {
$(message_area).attr('data-color', new_value);
}
// Regenerate style
var style = Message.generateStyle(hash);
// Any style to apply?
if(style)
if(style) {
$(message_area).attr('style', style);
else
} else {
$(message_area).removeAttr('style');
}
}).placeholder();
// Change event on text style checkboxes
$(style).change(function() {
var this_sel = $(this);
// Get current type
var style_data = 'data-' + $(this).attr('class');
var style_data = 'data-' + this_sel.attr('class');
// Checked checkbox?
if($(this).filter(':checked').size())
if(this_sel.filter(':checked').size()) {
$(message_area).attr(style_data, true);
else
} else {
$(message_area).removeAttr(style_data);
}
});
// Update the textarea style when it is changed
@ -383,10 +404,11 @@ var Tooltip = (function () {
var style = Message.generateStyle(hash);
// Any style to apply?
if(style)
if(style) {
$(message_area).attr('style', style);
else
} else {
$(message_area).removeAttr('style');
}
// Focus again on the message textarea
$(document).oneTime(10, function() {
@ -410,24 +432,31 @@ var Tooltip = (function () {
// Upload form submit event
$(path_tooltip + ' #oob-upload').submit(function() {
if($(path_tooltip + ' #oob-upload input[type="file"]').val())
$(this).ajaxSubmit(oob_upload_options);
var this_sel = $(this);
if($(path_tooltip + ' #oob-upload input[type="file"]').val()) {
this_sel.ajaxSubmit(oob_upload_options);
}
return false;
});
// Upload input change event
$(path_tooltip + ' #oob-upload input[type="file"]').change(function() {
if($(this).val())
var this_sel = $(this);
if(this_sel.val()) {
$(path_tooltip + ' #oob-upload').ajaxSubmit(oob_upload_options);
}
return false;
});
// Input click event
$(path_tooltip + ' #oob-upload input[type="file"], ' + path_tooltip + ' #oob-upload input[type="submit"]').click(function() {
if(Common.exists(path_tooltip + ' #oob-upload input[type="reset"]'))
if(Common.exists(path_tooltip + ' #oob-upload input[type="reset"]')) {
return;
}
// Lock the bubble
$(path_bubble).addClass('locked');
@ -569,17 +598,21 @@ var Tooltip = (function () {
// Apply the options to the style selector
$(bubble_style + ' input[type="checkbox"]').each(function() {
var this_sel = $(this);
// Current input enabled?
if(message_area.attr('data-' + $(this).attr('class')))
$(this).attr('checked', true);
if(message_area.attr('data-' + this_sel.attr('class'))) {
this_sel.attr('checked', true);
}
});
// Apply message color
if(color) {
if($(bubble_style + ' a.color[data-color="' + color + '"]').size())
if($(bubble_style + ' a.color[data-color="' + color + '"]').size()) {
$(bubble_style + ' a.color[data-color="' + color + '"]').addClass('selected');
else
} else {
$(bubble_style + ' div.color-hex input.hex-value').val(color);
}
}
} catch(e) {
Console.error('Tooltip.loadStyleSelector', e);

View file

@ -298,8 +298,9 @@ var UserInfos = (function () {
var path = '#userinfos[data-last="' + id + '"]';
// End if session does not exist
if(!Common.exists(path))
if(!Common.exists(path)) {
return;
}
if(iq && (iq.getType() == 'result')) {
// Get the values
@ -313,8 +314,9 @@ var UserInfos = (function () {
seconds = parseInt(seconds);
// Active user
if(seconds <= 60)
if(seconds <= 60) {
last = Common._e("User currently active");
}
// Inactive user
else {
@ -325,12 +327,14 @@ var UserInfos = (function () {
var date = date_last.toLocaleString();
// Offline user
if(from.indexOf('/') == -1)
if(from.indexOf('/') == -1) {
last = Common.printf(Common._e("Last seen: %s"), date);
}
// Online user
else
else {
last = Common.printf(Common._e("Inactive since: %s"), date);
}
}
// Append this text
@ -363,8 +367,9 @@ var UserInfos = (function () {
var path = '#userinfos[data-version="' + id + '"]';
// End if session does not exist
if(!Common.exists(path))
if(!Common.exists(path)) {
return;
}
// Extract the reply data
if(iq && (iq.getType() == 'result')) {
@ -375,14 +380,18 @@ var UserInfos = (function () {
var os = $(xml).find('os').text();
// Put the values together
if(name && version)
if(name && version) {
name = name + ' ' + version;
}
// Display the values
if(name)
if(name) {
$(path + ' #BUDDY-CLIENT').text(name);
if(os)
}
if(os) {
$(path + ' #BUDDY-SYSTEM').text(os);
}
Console.log('Software version received: ' + Common.fullXID(Common.getStanzaFrom(iq)));
}
@ -410,8 +419,9 @@ var UserInfos = (function () {
var path = '#userinfos[data-time="' + id + '"]';
// End if session does not exist
if(!Common.exists(path))
if(!Common.exists(path)) {
return;
}
if(iq && (iq.getType() == 'result')) {
// Get the values
@ -422,8 +432,9 @@ var UserInfos = (function () {
// Any UTC?
if(utc) {
// Add the TZO if there's no one
if(tzo && utc.match(/^(.+)Z$/))
if(tzo && utc.match(/^(.+)Z$/)) {
utc = RegExp.$1 + tzo;
}
// Get the local date string
var local_string = Date.hrTime(utc);
@ -454,8 +465,9 @@ var UserInfos = (function () {
try {
var selector = $('#userinfos .content');
if(!selector.hasClass('vcard') && !selector.hasClass('last') && !selector.hasClass('version') && !selector.hasClass('time'))
if(!selector.hasClass('vcard') && !selector.hasClass('last') && !selector.hasClass('version') && !selector.hasClass('time')) {
$('#userinfos .wait').hide();
}
} catch(e) {
Console.error('UserInfos.wait', e);
}
@ -478,8 +490,9 @@ var UserInfos = (function () {
// Necessary to update?
var old_value = DataStore.getDB(Connection.desktop_hash, 'rosternotes', xid);
if((old_value == value) || (!old_value && !value))
if((old_value == value) || (!old_value && !value)) {
return false;
}
// Update the database
DataStore.setDB(Connection.desktop_hash, 'rosternotes', xid, value);
@ -502,8 +515,9 @@ var UserInfos = (function () {
var cur_xid = RegExp.$1;
var cur_value = DataStore.storageDB.getItem(current);
if(cur_xid && cur_value)
if(cur_xid && cur_value) {
storage.appendChild(iq.buildNode('note', {'jid': cur_xid, 'xmlns': NS_ROSTERNOTES}, cur_value));
}
}
}
@ -526,10 +540,15 @@ var UserInfos = (function () {
self.switchTab = function(id) {
try {
$('#userinfos .content .one-lap').hide();
$('#userinfos .content .info' + id).show();
$('#userinfos .tab a').removeClass('tab-active');
$('#userinfos .tab a[data-key="' + id + '"]').addClass('tab-active');
var userinfos_sel = $('#userinfos');
var content_sel = userinfos_sel.find('.content');
var tab_link_sel = userinfos_sel.find('.tab a');
content_sel.find('.one-lap').hide();
content_sel.find('.info' + id).show();
tab_link_sel.removeClass('tab-active');
tab_link_sel.filter('[data-key="' + id + '"]').addClass('tab-active');
} catch(e) {
Console.error('UserInfos.switchTab', e);
} finally {
@ -582,12 +601,15 @@ var UserInfos = (function () {
try {
// Click events
$('#userinfos .tab a').click(function() {
var this_sel = $(this);
// Yet active?
if($(this).hasClass('tab-active'))
if(this_sel.hasClass('tab-active')) {
return false;
}
// Switch to the good tab
var key = parseInt($(this).attr('data-key'));
var key = parseInt(this_sel.attr('data-key'));
return self.switchTab(key);
});

View file

@ -52,8 +52,9 @@ var Utils = (function () {
try {
// HTTPS not allowed
if((HTTPS_STORAGE != 'on') && url.match(/^https(.+)/))
if((HTTPS_STORAGE != 'on') && url.match(/^https(.+)/)) {
url = 'http' + RegExp.$1;
}
return url;
} catch(e) {
@ -217,28 +218,34 @@ var Utils = (function () {
var browser_version = BrowserDetect.version;
// No DOM storage
if(!DataStore.hasDB() || !DataStore.hasPersistent())
if(!DataStore.hasDB() || !DataStore.hasPersistent()) {
return true;
}
// Obsolete IE
if((browser_name == 'Explorer') && (browser_version < 8))
if((browser_name == 'Explorer') && (browser_version < 8)) {
return true;
}
// Obsolete Chrome
if((browser_name == 'Chrome') && (browser_version < 7))
if((browser_name == 'Chrome') && (browser_version < 7)) {
return true;
}
// Obsolete Safari
if((browser_name == 'Safari') && (browser_version < 4))
if((browser_name == 'Safari') && (browser_version < 4)) {
return true;
}
// Obsolete Firefox
if((browser_name == 'Firefox') && (browser_version < 3.5))
if((browser_name == 'Firefox') && (browser_version < 3.5)) {
return true;
}
// Obsolete Opera
if((browser_name == 'Opera') && (browser_version < 9))
if((browser_name == 'Opera') && (browser_version < 9)) {
return true;
}
return false;
} catch(e) {
@ -585,6 +592,33 @@ var Utils = (function () {
};
/**
* Removes duplicate values from array
* @public
* @param {object} arr
* @return {object}
*/
self.uniqueArrayValues = function(arr) {
try {
var a = arr.concat();
for(var i = 0; i < a.length; ++i) {
for(var j = i + 1; j < a.length; ++j) {
if(a[i] === a[j]) {
a.splice(j--, 1);
}
}
}
return a;
} catch(e) {
Console.error('Utils.uniqueArrayValues', e);
}
};
/**
* Converts a string to an array
* @public
@ -603,10 +637,11 @@ var Utils = (function () {
var string_split = string.split(',');
for(var i in string_split) {
if(string_split[i])
if(string_split[i]) {
array.push(string_split[i]);
else
} else {
array.push('');
}
}
}
@ -634,8 +669,9 @@ var Utils = (function () {
try {
// Nothing?
if(!array || !array.length)
if(!array || !array.length) {
return 0;
}
// Read the index of the value
var index = 0;

View file

@ -272,7 +272,7 @@ var vCard = (function () {
$('#USER-PHOTO-TYPE').val(aType);
$('#USER-PHOTO-BINVAL').val(aBinval);
// We display the avatar !
// We display the avatar!
$('#vcard .avatar-container').replaceWith('<div class="avatar-container"><img class="avatar" src="data:' + aType + ';base64,' + aBinval + '" alt="" /></div>');
}
@ -374,9 +374,7 @@ var vCard = (function () {
// Send the IQ
con.send(iq, self.handleUser);
}
else {
} else {
// Show the wait icon
$('#userinfos .wait').show();
@ -456,12 +454,14 @@ var vCard = (function () {
var values_yet = [];
$(iqNode).find('vCard').children().each(function() {
var this_sel = $(this);
// Read the current parent node name
var tokenname = (this).nodeName.toUpperCase();
// Node with a parent
if($(this).children().size()) {
$(this).children().each(function() {
if(this_sel.children().size()) {
this_sel.children().each(function() {
// Get the node values
var currentID = tokenname + '-' + (this).nodeName.toUpperCase();
var currentText = $(this).text();
@ -473,10 +473,11 @@ var vCard = (function () {
// Userinfos viewer popup
if((type == 'buddy') && currentText) {
if(currentID == 'EMAIL-USERID')
if(currentID == 'EMAIL-USERID') {
$(path_userInfos + ' #BUDDY-' + currentID).html('<a href="mailto:' + currentText.htmlEnc() + '" target="_blank">' + currentText.htmlEnc() + '</a>');
else
} else {
$(path_userInfos + ' #BUDDY-' + currentID).text(currentText.htmlEnc());
}
}
// Profile editor popup
@ -505,8 +506,9 @@ var vCard = (function () {
// URL modification
if(tokenname == 'URL') {
// No http:// or https:// prefix, we should add it
if(!currentText.match(/^https?:\/\/(.+)/))
if(!currentText.match(/^https?:\/\/(.+)/)) {
currentText = 'http://' + currentText;
}
currentText = '<a href="' + currentText + '" target="_blank">' + currentText.htmlEnc() + '</a>';
}
@ -525,8 +527,9 @@ var vCard = (function () {
}
// Profile editor popup
else if(type == 'user')
else if(type == 'user') {
$(path_vcard + ' #USER-' + tokenname).val(currentText);
}
// Avoid duplicating the value
values_yet.push(tokenname);
@ -556,9 +559,7 @@ var vCard = (function () {
aBinval = $('#USER-PHOTO-BINVAL').val();
aType = $('#USER-PHOTO-TYPE').val();
aContainer = path_vcard + ' .avatar-container';
}
else {
} else {
aBinval = $(iqNode).find('BINVAL:first').text();
aType = $(iqNode).find('TYPE:first').text();
aContainer = path_userInfos + ' .avatar-container';
@ -578,8 +579,10 @@ var vCard = (function () {
$(path_vcard + ' .avatar').remove();
}
var avatar_src = ('data:' + aType + ';base64,' + aBinval);
// We display the avatar we have just received
$(aContainer).replaceWith('<div class="avatar-container"><img class="avatar" src="data:' + aType + ';base64,' + aBinval + '" alt="" /></div>');
$(aContainer).replaceWith('<div class="avatar-container"><img class="avatar" src="' + avatar_src + '" alt="" /></div>');
}
else if(type == 'buddy') {
@ -668,10 +671,11 @@ var vCard = (function () {
var tagname = Common.explodeThis('-', item_id, 0);
var cur_node;
if(node.getElementsByTagName(tagname).length > 0)
if(node.getElementsByTagName(tagname).length > 0) {
cur_node = node.getElementsByTagName(tagname).item(0);
else
} else {
cur_node = node.appendChild(stanza.buildNode(tagname, {'xmlns': namespace}));
}
cur_node.appendChild(
stanza.buildNode(
@ -874,18 +878,22 @@ var vCard = (function () {
// Keyboard events
$('#vcard input[type="text"]').keyup(function(e) {
// Enter pressed: send the vCard
if((e.keyCode == 13) && !$('#vcard .finish.save').hasClass('disabled'))
if((e.keyCode == 13) && !$('#vcard .finish.save').hasClass('disabled')) {
return self.send();
}
});
// Click events
$('#vcard .tab a').click(function() {
var this_sel = $(this);
// Yet active?
if($(this).hasClass('tab-active'))
if(this_sel.hasClass('tab-active')) {
return false;
}
// Switch to the good tab
var key = parseInt($(this).attr('data-key'));
var key = parseInt(this_sel.attr('data-key'));
return self.switchTab(key);
});
@ -895,10 +903,15 @@ var vCard = (function () {
});
$('#vcard .bottom .finish').click(function() {
if($(this).is('.cancel'))
var this_sel = $(this);
if(this_sel.is('.cancel')) {
return self.close();
if($(this).is('.save') && !$(this).hasClass('disabled'))
}
if(this_sel.is('.save') && !this_sel.hasClass('disabled')) {
return self.send();
}
return false;
});
@ -912,16 +925,22 @@ var vCard = (function () {
// Avatar upload form submit event
$('#vcard-avatar').submit(function() {
if($('#vcard .wait').is(':hidden') && $('#vcard .avatar-info.avatar-wait').is(':hidden') && $('#vcard-avatar input[type="file"]').val())
if($('#vcard .wait').is(':hidden') &&
$('#vcard .avatar-info.avatar-wait').is(':hidden') &&
$('#vcard-avatar input[type="file"]').val()) {
$(this).ajaxSubmit(avatar_options);
}
return false;
});
// Avatar upload input change event
$('#vcard-avatar input[type="file"]').change(function() {
if($('#vcard .wait').is(':hidden') && $('#vcard .avatar-info.avatar-wait').is(':hidden') && $(this).val())
if($('#vcard .wait').is(':hidden') &&
$('#vcard .avatar-info.avatar-wait').is(':hidden') &&
$(this).val()) {
$('#vcard-avatar').ajaxSubmit(avatar_options);
}
return false;
});

View file

@ -203,6 +203,7 @@ var Welcome = (function () {
// Update the "save" button if all is okay
if(!Common.exists(tab + '.tab-missing')) {
var finish = welcome + '.finish.';
$(finish + 'save').show();
$(finish + 'next').hide();
}
@ -280,19 +281,22 @@ var Welcome = (function () {
$('#welcome a.box').each(function() {
var current = '0';
if($(this).hasClass('enabled'))
if($(this).hasClass('enabled')) {
current = '1';
}
array.push(current);
});
// If XMPP links is enabled
if(array[2] == '1')
if(array[2] == '1') {
Utils.xmppLinksHandler();
}
// If offline buddies showing is enabled
if(array[4] == '1')
if(array[4] == '1') {
Interface.showAllBuddies('welcome');
}
// If archiving is supported by the server
if(Features.enabledMAM()) {
@ -336,8 +340,9 @@ var Welcome = (function () {
var next = 1;
var missing = '#welcome .tab a.tab-missing';
if(Common.exists(missing))
if(Common.exists(missing)) {
next = parseInt($(missing + ':first').attr('data-step'));
}
// Switch to the next step
self.switchTab(next);
@ -360,26 +365,36 @@ var Welcome = (function () {
try {
// Click events
$('#welcome .tab a').click(function() {
var this_sel = $(this);
// Switch to the good tab
var key = parseInt($(this).attr('data-step'));
var key = parseInt(this_sel.attr('data-step'));
return self.switchTab(key);
});
$('#welcome a.box:not(.share)').click(function() {
if($(this).hasClass('enabled'))
$(this).removeClass('enabled').attr('title', Common._e("Click to enable"));
else
$(this).addClass('enabled').attr('title', Common._e("Click to disable"));
var this_sel = $(this);
if(this_sel.hasClass('enabled')) {
this_sel.removeClass('enabled').attr('title', Common._e("Click to enable"));
} else {
this_sel.addClass('enabled').attr('title', Common._e("Click to disable"));
}
return false;
});
$('#welcome .bottom .finish').click(function() {
if($(this).is('.next'))
var this_sel = $(this);
if(this_sel.is('.next')) {
return self.next();
if($(this).is('.save'))
}
if(this_sel.is('.save')) {
return self.save();
}
return false;
});

View file

@ -35,11 +35,9 @@ var XMPPLinks = (function () {
link = Common.explodeThis(':', link, 1);
// The XMPP URI has no "?"
if(link.indexOf('?') == -1)
if(link.indexOf('?') == -1) {
Chat.checkCreate(link, 'chat');
// Parse the URI
else {
} else {
var xid = Common.explodeThis('?', link, 0);
var action = Common.explodeThis('?', link, 1);
@ -88,11 +86,13 @@ var XMPPLinks = (function () {
* Gets the links vars (get parameters in URL)
*/
self.links_var = (function() {
var hash;
var vars = [];
var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
for(var i = 0; i < hashes.length; i++) {
var hash = hashes[i].split('=');
hash = hashes[i].split('=');
vars.push(hash[0]);
vars[hash[0]] = $.trim(decodeURIComponent(hash[1]));
}

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,254 @@
/*
Jappix - An open social platform
This is the call CSS stylesheet for Jappix
-------------------------------------------------
License: AGPL
Author: Valérian Saliou
*/
.videochat_box {
display: none;
}
.videochat_box .videochat_items {
background: #ededed;
border: 1px solid rgb(0,0,0);
border: 1px solid rgba(0,0,0,0.8);
text-shadow: none;
min-width: 550px;
min-height: 420px;
overflow: hidden;
position: absolute;
left: 100px;
right: 100px;
top: 40px;
bottom: 40px;
-moz-box-shadow: 0 0 12px rgba(0,0,0,0.4);
-webkit-box-shadow: 0 0 12px rgba(0,0,0,0.4);
box-shadow: 0 0 12px rgba(0,0,0,0.4);
}
.videochat_box .videochat_items .topbar {
background: rgb(0,0,0);
background: rgba(0,0,0,0.5);
border-bottom: 1px solid rgb(0,0,0);
border-bottom: 1px solid rgba(0,0,0,0.15);
color: #ffffff;
text-shadow: 0 1px 1px rgb(0,0,0);
text-shadow: 0 1px 1px rgba(0,0,0,0.5);
height: 40px;
position: absolute;
left: 0;
right: 0;
top: 0;
z-index: 4;
-moz-box-shadow: 0 0 5px rgba(0,0,0,0.25);
-webkit-box-shadow: 0 0 5px rgba(0,0,0,0.25);
box-shadow: 0 0 5px rgba(0,0,0,0.25);
}
.videochat_box .videochat_items .topbar .controls,
.videochat_box .videochat_items .topbar .elapsed {
float: left;
}
html[dir="rtl"] .videochat_box .videochat_items .topbar .controls,
html[dir="rtl"] .videochat_box .videochat_items .topbar .elapsed {
float: right;
}
html[dir="rtl"] .videochat_box .videochat_items .topbar .controls {
margin-left: 0;
margin-right: 50px;
}
.videochat_box .videochat_items .topbar .controls a {
margin-top: 7px;
float: left;
}
html[dir="rtl"] .videochat_box .videochat_items .topbar .controls a {
float: right;
}
.videochat_box .videochat_items .topbar .controls a,
.call-content .call-notify .notification-content .reply-buttons a.reply-button {
border-width: 1px;
border-style: solid;
font-size: 10px;
color: #ffffff;
text-transform: uppercase;
text-decoration: none;
padding: 5px 6px 6px 6px;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
}
.videochat_box .videochat_items .topbar .controls a:active,
.call-content .call-notify .notification-content .reply-buttons a.reply-button:active {
padding-top: 6px;
padding-bottom: 5px;
-webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.25) inset;
-moz-box-shadow: 0 1px 3px rgba(0,0,0,0.25) inset;
box-shadow: 0 1px 3px rgba(0,0,0,0.25) inset;
}
.videochat_box .videochat_items .topbar .controls a .icon {
width: 14px;
height: 14px;
margin: -1px 7px 0 2px;
float: left;
}
.videochat_box .videochat_items .topbar .controls a.stop,
.videochat_box .videochat_items .topbar .controls a.leave,
.call-content .call-notify .notification-content .reply-buttons a.reply-button.red {
background: #cc283f;
border-color: #5e121d;
}
.videochat_box .videochat_items .topbar .controls a.stop:active,
.videochat_box .videochat_items .topbar .controls a.leave:active,
.call-content .call-notify .notification-content .reply-buttons a.reply-button.red:active {
background: #a92134;
border-color: #480e16;
}
.videochat_box .videochat_items .topbar .controls a.stop .icon,
.videochat_box .videochat_items .topbar .controls a.leave .icon {
background-position: 0 -62px;
}
.call-content .call-notify .notification-content .reply-buttons a.reply-button.green {
background: #5ea45e;
border-color: #1a2e1a;
}
.call-content .call-notify .notification-content .reply-buttons a.reply-button.green:active {
background: #549253;
border-color: #0f1a0f;
}
.videochat_box .videochat_items .topbar .controls a.mute,
.videochat_box .videochat_items .topbar .controls a.unmute,
.call-content .call-notify .notification-content .reply-buttons a.reply-button.blue {
background: #6e8dc5;
border-color: #303d55;
}
.videochat_box .videochat_items .topbar .controls a.mute,
.videochat_box .videochat_items .topbar .controls a.unmute {
margin-left: 6px;
}
html[dir="rtl"] .videochat_box .videochat_items .topbar .controls a.mute,
html[dir="rtl"] .videochat_box .videochat_items .topbar .controls a.unmute {
margin-left: 0;
margin-right: 6px;
}
.videochat_box .videochat_items .topbar .controls a.mute:active,
.videochat_box .videochat_items .topbar .controls a.unmute:active,
.call-content .call-notify .notification-content .reply-buttons a.reply-button.blue:active {
background: #6480b1;
border-color: #222b3b;
}
.videochat_box .videochat_items .topbar .controls a.mute .icon {
background-position: 0 -81px;
}
.videochat_box .videochat_items .topbar .controls a.unmute {
display: none;
}
.videochat_box .videochat_items .topbar .controls a.unmute .icon {
background-position: 0 -100px;
}
.videochat_box .videochat_items .topbar .elapsed {
background: rgb(0,0,0);
background: rgba(0,0,0,0.1);
border: 1px solid rgb(255,255,255);
border: 1px solid rgba(255,255,255,0.25);
outline: 1px solid rgb(0,0,0);
outline: 1px solid rgba(0,0,0,0.2);
font-size: 11px;
font-weight: bold;
letter-spacing: 2px;
margin: 10px 0 0 46px;
padding: 2px 6px;
}
html[dir="rtl"] .videochat_box .videochat_items .topbar .elapsed {
margin-left: 0;
margin-right: 46px;
}
.videochat_box .videochat_items .topbar .actions {
margin: 7px 15px 0 0;
float: right;
}
html[dir="rtl"] .videochat_box .videochat_items .topbar .actions {
margin-right: 0;
margin-left: 15px;
float: left;
}
.videochat_box .videochat_items .topbar .actions a {
float: left;
}
.videochat_box .videochat_items .topbar .actions a.close {
background-position: 0 -44px;
width: 18px;
height: 12px;
margin-top: 6px;
}
.videochat_box .videochat_items .local_video {
background-position: 0 -56px;
border: 1px solid rgb(0,0,0);
border: 1px solid rgba(0,0,0,0.5);
width: 180px;
height: 101px;
opacity: 0.6;
overflow: hidden;
position: absolute;
left: 18px;
bottom: 18px;
z-index: 3;
-moz-box-shadow: 0 0 8px rgba(0,0,0,0.25);
-webkit-box-shadow: 0 0 8px rgba(0,0,0,0.25);
box-shadow: 0 0 8px rgba(0,0,0,0.25);
-webkit-transition: all 0.4s ease-in-out 0.2s;
-moz-transition: all 0.4s ease-in-out 0.2s;
-o-transition: all 0.4s ease-in-out 0.2s;
transition: all 0.4s ease-in-out 0.2s;
}
html[dir="rtl"] .videochat_box .videochat_items .local_video {
left: auto;
right: 18px;
}
.videochat_box .videochat_items .local_video:disabled {
opacity: 0.2 !important;
}
.videochat_box .videochat_items .local_video:hover {
width: 320px;
height: 180px;
opacity: 1;
cursor: pointer;
}
.videochat_box .videochat_items .local_video video {
width: 100%;
}

View file

@ -597,7 +597,8 @@ html[dir="rtl"] #home .right .navigation a {
background: -webkit-gradient(linear, left top, left bottom, from(#e4eef9), to(#c5e1ff));
background: -webkit-linear-gradient(top, #e4eef9 0%, #c5e1ff 100%);
background: -o-linear-gradient(top, #e4eef9 0%, #c5e1ff 100%);
font-size: 13.4px;
font-size: 11px !important;
overflow: hidden;
position: absolute;
top: 0;
bottom: 0;
@ -693,6 +694,22 @@ html[dir="rtl"] #home .right .navigation a {
left: 10px;
}
#home .friendsview .friends .group.standard br {
display: none;
}
#home .friendsview .friends .group.standard a {
text-align: center;
text-decoration: underline;
margin-bottom: 1px;
float: left;
width: 50%;
}
#home .friendsview .friends .group.standard a:nth-child(even) {
float: right;
}
#home .friendsview .friends a.group.refer {
width: 81px;
padding-left: 10px;

View file

@ -56,8 +56,8 @@ Author: Valérian Saliou
background-repeat: no-repeat;
}
.jingle-images {
background-image: url(../images/sprites/jingle.png);
.call-images {
background-image: url(../images/sprites/call.png);
background-repeat: no-repeat;
}

View file

@ -1,7 +1,7 @@
/*
Jappix - An open social platform
This is the discovery CSS stylesheet for Jappix
This is the Jingle CSS stylesheet for Jappix
-------------------------------------------------
@ -10,47 +10,6 @@ Author: Valérian Saliou
*/
#jingle {
display: none;
}
#jingle .videobox {
background: #ededed;
border: 1px solid rgb(0,0,0);
border: 1px solid rgba(0,0,0,0.8);
text-shadow: none;
min-width: 550px;
min-height: 420px;
overflow: hidden;
position: absolute;
left: 100px;
right: 100px;
top: 40px;
bottom: 40px;
-moz-box-shadow: 0 0 12px rgba(0,0,0,0.4);
-webkit-box-shadow: 0 0 12px rgba(0,0,0,0.4);
box-shadow: 0 0 12px rgba(0,0,0,0.4);
}
#jingle .videobox .topbar {
background: rgb(0,0,0);
background: rgba(0,0,0,0.5);
border-bottom: 1px solid rgb(0,0,0);
border-bottom: 1px solid rgba(0,0,0,0.15);
color: #ffffff;
text-shadow: 0 1px 1px rgb(0,0,0);
text-shadow: 0 1px 1px rgba(0,0,0,0.5);
height: 40px;
position: absolute;
left: 0;
right: 0;
top: 0;
z-index: 4;
-moz-box-shadow: 0 0 5px rgba(0,0,0,0.25);
-webkit-box-shadow: 0 0 5px rgba(0,0,0,0.25);
box-shadow: 0 0 5px rgba(0,0,0,0.25);
}
#jingle .videobox .topbar .card {
margin: 4px 0 0 12px;
}
@ -62,17 +21,13 @@ html[dir="rtl"] #jingle .videobox .topbar .card {
#jingle .videobox .topbar .card,
#jingle .videobox .topbar .card .avatar-container,
#jingle .videobox .topbar .card .identity,
#jingle .videobox .topbar .controls,
#jingle .videobox .topbar .elapsed {
#jingle .videobox .topbar .card .identity {
float: left;
}
html[dir="rtl"] #jingle .videobox .topbar .card,
html[dir="rtl"] #jingle .videobox .topbar .card .avatar-container,
html[dir="rtl"] #jingle .videobox .topbar .card .identity,
html[dir="rtl"] #jingle .videobox .topbar .controls,
html[dir="rtl"] #jingle .videobox .topbar .elapsed {
html[dir="rtl"] #jingle .videobox .topbar .card .identity {
float: right;
}
@ -115,192 +70,8 @@ html[dir="rtl"] #jingle .videobox .topbar .card .identity {
margin-left: 50px;
}
html[dir="rtl"] #jingle .videobox .topbar .controls {
margin-left: 0;
margin-right: 50px;
}
#jingle .videobox .topbar .controls a {
margin-top: 7px;
float: left;
}
html[dir="rtl"] #jingle .videobox .topbar .controls a {
float: right;
}
#jingle .videobox .topbar .controls a,
.jingle-content .jingle-notify .notification-content .reply-buttons a.reply-button {
border-width: 1px;
border-style: solid;
font-size: 10px;
color: #ffffff;
text-transform: uppercase;
text-decoration: none;
padding: 5px 6px 6px 6px;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
}
#jingle .videobox .topbar .controls a:active,
.jingle-content .jingle-notify .notification-content .reply-buttons a.reply-button:active {
padding-top: 6px;
padding-bottom: 5px;
-webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.25) inset;
-moz-box-shadow: 0 1px 3px rgba(0,0,0,0.25) inset;
box-shadow: 0 1px 3px rgba(0,0,0,0.25) inset;
}
#jingle .videobox .topbar .controls a .icon {
width: 14px;
height: 14px;
margin: -1px 7px 0 2px;
float: left;
}
#jingle .videobox .topbar .controls a.stop,
.jingle-content .jingle-notify .notification-content .reply-buttons a.reply-button.red {
background: #cc283f;
border-color: #5e121d;
}
#jingle .videobox .topbar .controls a.stop:active,
.jingle-content .jingle-notify .notification-content .reply-buttons a.reply-button.red:active {
background: #a92134;
border-color: #480e16;
}
#jingle .videobox .topbar .controls a.stop .icon {
background-position: 0 -62px;
}
.jingle-content .jingle-notify .notification-content .reply-buttons a.reply-button.green {
background: #5ea45e;
border-color: #1a2e1a;
}
.jingle-content .jingle-notify .notification-content .reply-buttons a.reply-button.green:active {
background: #549253;
border-color: #0f1a0f;
}
#jingle .videobox .topbar .controls a.mute,
#jingle .videobox .topbar .controls a.unmute,
.jingle-content .jingle-notify .notification-content .reply-buttons a.reply-button.blue {
background: #6e8dc5;
border-color: #303d55;
}
#jingle .videobox .topbar .controls a.mute,
#jingle .videobox .topbar .controls a.unmute {
margin-left: 6px;
}
html[dir="rtl"] #jingle .videobox .topbar .controls a.mute,
html[dir="rtl"] #jingle .videobox .topbar .controls a.unmute {
margin-left: 0;
margin-right: 6px;
}
#jingle .videobox .topbar .controls a.mute:active,
#jingle .videobox .topbar .controls a.unmute:active,
.jingle-content .jingle-notify .notification-content .reply-buttons a.reply-button.blue:active {
background: #6480b1;
border-color: #222b3b;
}
#jingle .videobox .topbar .controls a.mute .icon {
background-position: 0 -81px;
}
#jingle .videobox .topbar .controls a.unmute {
display: none;
}
#jingle .videobox .topbar .controls a.unmute .icon {
background-position: 0 -100px;
}
#jingle .videobox .topbar .elapsed {
background: rgb(0,0,0);
background: rgba(0,0,0,0.1);
border: 1px solid rgb(255,255,255);
border: 1px solid rgba(255,255,255,0.25);
outline: 1px solid rgb(0,0,0);
outline: 1px solid rgba(0,0,0,0.2);
font-size: 11px;
font-weight: bold;
letter-spacing: 2px;
margin: 10px 0 0 46px;
padding: 2px 6px;
}
html[dir="rtl"] #jingle .videobox .topbar .elapsed {
margin-left: 0;
margin-right: 46px;
}
#jingle .videobox .topbar .actions {
margin: 7px 15px 0 0;
float: right;
}
html[dir="rtl"] #jingle .videobox .topbar .actions {
margin-right: 0;
margin-left: 15px;
float: left;
}
#jingle .videobox .topbar .actions a {
float: left;
}
#jingle .videobox .topbar .actions a.close {
background-position: 0 -44px;
width: 18px;
height: 12px;
margin-top: 6px;
}
#jingle .videobox .local_video {
background-position: 0 -56px;
border: 1px solid rgb(0,0,0);
border: 1px solid rgba(0,0,0,0.5);
width: 180px;
height: 101px;
opacity: 0.6;
overflow: hidden;
position: absolute;
left: 18px;
bottom: 18px;
z-index: 3;
-moz-box-shadow: 0 0 8px rgba(0,0,0,0.25);
-webkit-box-shadow: 0 0 8px rgba(0,0,0,0.25);
box-shadow: 0 0 8px rgba(0,0,0,0.25);
-webkit-transition: all 0.4s ease-in-out 0.2s;
-moz-transition: all 0.4s ease-in-out 0.2s;
-o-transition: all 0.4s ease-in-out 0.2s;
transition: all 0.4s ease-in-out 0.2s;
}
html[dir="rtl"] #jingle .videobox .local_video {
left: auto;
right: 18px;
}
#jingle .videobox .local_video:disabled {
opacity: 0.2 !important;
}
#jingle .videobox .local_video:hover {
width: 320px;
height: 180px;
opacity: 1;
cursor: pointer;
}
#jingle .videobox .remote_video {
background-color: #000000;
width: 100%;
height: 100%;
position: absolute;
@ -311,6 +82,11 @@ html[dir="rtl"] #jingle .videobox .local_video {
z-index: 1;
}
#jingle .videobox .remote_video video {
width: 100%;
height: 100%;
}
#jingle .videobox .branding {
background-position: 0 0;
width: 39px;

View file

@ -114,6 +114,19 @@ input[type="radio"] {
border: 0 none !important;
}
input.input-reset {
background: transparent;
border: 0 none;
margin: 0;
padding: 0;
-moz-border-radius: 0;
-webkit-border-radius: 0;
border-radius: 0;
-moz-box-shadow: none;
-webkit-box-shadow: none;
box-shadow: none;
}
.please-complete,
.please-complete:hover,
.please-complete:focus {
@ -129,4 +142,5 @@ input[type="radio"] {
.clear {
clear: both !important;
display: block !important;
}

View file

@ -143,7 +143,7 @@ a {
}
#talk a.one-buddy {
display: none;
display: block;
background-color: #87a5ab;
border-bottom: 1px solid #5b8088;
text-shadow: 1px 1px 1px #5b8088;
@ -154,6 +154,7 @@ a {
}
#talk a.one-buddy:hover {
background-color: #8fb0b7;
cursor: pointer;
}
@ -248,7 +249,7 @@ a {
border-bottom: 1px solid #cbcbcb;
top: 23px;
left: 0;
bottom: 25px;
bottom: 37px;
overflow: auto;
text-align: left;
}

View file

@ -0,0 +1,700 @@
/*
Jappix - An open social platform
This is the Muji CSS stylesheet for Jappix
-------------------------------------------------
License: AGPL
Author: Valérian Saliou
*/
#muji .videochat_items {
min-width: 600px;
left: 60px;
right: 60px;
}
#muji .remote_container {
position: absolute;
left: 0;
right: 0;
bottom: 0;
top: 0;
}
/* Default video */
#muji .remote_container .remote_video_shaper {
overflow: hidden;
display: none;
float: left;
position: relative;
}
/* 1 video view */
#muji[data-count="1"] .remote_container .remote_video_shaper:nth-child(1) {
width: 100%;
height: 100%;
display: block;
}
/* 2 video views */
#muji[data-count="2"] .remote_container .remote_video_shaper:nth-child(1),
#muji[data-count="2"] .remote_container .remote_video_shaper:nth-child(2) {
width: 50%;
height: 100%;
display: block;
}
/* 3 video views */
#muji[data-count="3"] .remote_container .remote_video_shaper:nth-child(1),
#muji[data-count="3"] .remote_container .remote_video_shaper:nth-child(2),
#muji[data-count="3"] .remote_container .remote_video_shaper:nth-child(3) {
height: 50%;
display: block;
}
#muji[data-count="3"] .remote_container .remote_video_shaper:nth-child(1) {
width: 100%;
float: none;
}
#muji[data-count="3"] .remote_container .remote_video_shaper:nth-child(2),
#muji[data-count="3"] .remote_container .remote_video_shaper:nth-child(3) {
width: 50%;
}
/* 4 video views */
#muji[data-count="4"] .remote_container .remote_video_shaper:nth-child(1),
#muji[data-count="4"] .remote_container .remote_video_shaper:nth-child(2),
#muji[data-count="4"] .remote_container .remote_video_shaper:nth-child(3),
#muji[data-count="4"] .remote_container .remote_video_shaper:nth-child(4) {
height: 50%;
width: 50%;
display: block;
}
/* 5 video views */
#muji[data-count="5"] .remote_container .remote_video_shaper:nth-child(1),
#muji[data-count="5"] .remote_container .remote_video_shaper:nth-child(2),
#muji[data-count="5"] .remote_container .remote_video_shaper:nth-child(3),
#muji[data-count="5"] .remote_container .remote_video_shaper:nth-child(4),
#muji[data-count="5"] .remote_container .remote_video_shaper:nth-child(5) {
height: 50%;
display: block;
}
#muji[data-count="5"] .remote_container .remote_video_shaper:nth-child(1),
#muji[data-count="5"] .remote_container .remote_video_shaper:nth-child(2) {
width: 50%;
}
#muji[data-count="5"] .remote_container .remote_video_shaper:nth-child(3),
#muji[data-count="5"] .remote_container .remote_video_shaper:nth-child(4),
#muji[data-count="5"] .remote_container .remote_video_shaper:nth-child(5) {
width: 33.33333333%;
}
/* 6 video views */
#muji[data-count="6"] .remote_container .remote_video_shaper:nth-child(1),
#muji[data-count="6"] .remote_container .remote_video_shaper:nth-child(2),
#muji[data-count="6"] .remote_container .remote_video_shaper:nth-child(3),
#muji[data-count="6"] .remote_container .remote_video_shaper:nth-child(4),
#muji[data-count="6"] .remote_container .remote_video_shaper:nth-child(5),
#muji[data-count="6"] .remote_container .remote_video_shaper:nth-child(6) {
height: 50%;
width: 33.33333333%;
display: block;
}
#muji .remote_container .remote_video_shaper .label_username {
background: rgb(0,0,0);
background: rgba(0,0,0,0.6);
color: #ffffff;
font-size: 0.75em;
padding: 3px 6px 4px 10px;
position: absolute;
top: 7px;
left: 0;
display: none;
}
html[dir="rtl"] #muji .remote_container .remote_video_shaper .label_username {
padding-right: 10px;
padding-left: 6px;
left: auto;
right: 0;
}
#muji[data-count="1"] .remote_container .remote_video_shaper .label_username,
#muji[data-count="2"] .remote_container .remote_video_shaper .label_username,
#muji[data-count="3"] .remote_container .remote_video_shaper:nth-child(1) .label_username,
#muji[data-count="4"] .remote_container .remote_video_shaper:nth-child(n+1):nth-child(-n+2) .label_username,
#muji[data-count="5"] .remote_container .remote_video_shaper:nth-child(n+1):nth-child(-n+2) .label_username,
#muji[data-count="6"] .remote_container .remote_video_shaper:nth-child(n+1):nth-child(-n+3) .label_username {
top: 48px;
}
#muji .remote_container .remote_video_shaper:hover .label_username {
display: block;
}
#muji .empty_message {
text-align: center;
margin-top: -11px;
position: absolute;
left: 0;
right: 0;
top: 50%;
}
#muji .empty_message .text {
color: #ffffff;
letter-spacing: 1px;
font-size: 1.2em;
}
#muji .videoroom,
#muji .chatroom {
position: absolute;
top: 0;
bottom: 0;
}
#muji .videoroom {
background-color: #000000;
left: 0;
right: 280px;
}
html[dir="rtl"] #muji .videoroom {
right: 0;
left: 280px;
}
#muji .videoroom .topbar .controls {
margin-left: 18px;
}
html[dir="rtl"] #muji .videoroom .topbar .controls {
margin-right: 18px;
}
#muji .videoroom .topbar .elapsed {
margin-left: 80px;
}
html[dir="rtl"] #muji .videoroom .topbar .elapsed {
margin-right: 80px;
}
#muji .chatroom {
background: #ffffff;
width: 280px;
right: 0;
}
html[dir="rtl"] #muji .chatroom {
right: auto;
left: 0;
}
#muji .videoroom .local_video {
width: 140px;
height: 78px;
}
#muji .videoroom .local_video:hover {
width: 220px;
height: 123px;
}
#muji .chatroom .chatroom_participants {
background: #fcfcfc;
border-bottom: 1px solid #e1e1e1;
position: absolute;
top: 0;
left: 0;
right: 0;
z-index: 1;
}
#muji .chatroom .chatroom_participants .participants_default_view {
text-align: center;
height: 40px;
}
#muji .chatroom .chatroom_participants .participants_default_view .participants_counter,
#muji .chatroom .chatroom_participants .participants_default_view .participants_full {
color: #444444;
font-size: 0.9em;
font-weight: bold;
letter-spacing: 1px;
margin-top: 11px;
display: inline-block;
}
#muji .chatroom .chatroom_participants .participants_default_view .participants_full {
color: #5a6d7f;
font-size: 0.8em;
margin-left: 6px;
display: none;
}
html[dir="rtl"] #muji .chatroom .chatroom_participants .participants_default_view .participants_full {
margin-left: auto;
margin-right: 6px;
}
#muji .chatroom .chatroom_participants .participants_default_view .participants_invite {
background-position: 0 -287px;
width: 13px;
height: 13px;
opacity: 0.6;
display: block;
position: absolute;
top: 14px;
right: 16px;
}
html[dir="rtl"] #muji .chatroom .chatroom_participants .participants_default_view .participants_invite {
right: auto;
left: 16px;
}
#muji .chatroom .chatroom_participants .participants_default_view .participants_invite:hover,
#muji .chatroom .chatroom_participants .participants_default_view .participants_invite:focus {
opacity: 1;
}
#muji .chatroom .chatroom_participants .participants_invite_box {
border-top: 1px solid #e1e1e1;
display: none;
}
#muji .chatroom .chatroom_participants .participants_invite_box .participants_invite_list {
border-bottom: 1px solid #e1e1e1;
padding: 4px 2px 2px 6px;
display: none;
}
#muji .chatroom .chatroom_participants .participants_invite_box .participants_invite_list .invite_one {
background: #d7e2f4;
border: 1px solid #aab9f4;
font-size: 0.75em;
margin: 0 4px 3px 0;
padding: 2px 4px;
display: inline-block;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
}
#muji .chatroom .chatroom_participants .participants_invite_box .participants_invite_list .invite_one.invite_unsupported {
background: #f49d90;
border-color: #de8780;
color: #95443e;
}
#muji .chatroom .chatroom_participants .participants_invite_box .participants_invite_list .invite_one .invite_one_remove {
background-position: 0 -300px;
width: 9px;
height: 9px;
margin-left: 3px;
margin-top: 1px;
display: inline-block;
}
html[dir="rtl"] #muji .chatroom .chatroom_participants .participants_invite_box .participants_invite_list .invite_one .invite_one_remove {
margin-left: auto;
margin-right: 3px;
}
#muji .chatroom .chatroom_participants .participants_invite_box .participants_invite_list .invite_one.invite_unsupported .invite_one_remove {
background-position: 0 -309px;
}
#muji .chatroom .chatroom_participants .participants_invite_box .participants_invite_list .invite_one .invite_one_remove:hover,
#muji .chatroom .chatroom_participants .participants_invite_box .participants_invite_list .invite_one .invite_one_remove:focus,
#muji .chatroom .chatroom_participants .participants_invite_box .participants_invite_list .invite_one .invite_one_remove:active {
background-position: 1px -317px;
margin-left: 2px;
margin-right: -1px;
margin-bottom: -1px;
padding: 1px;
-moz-border-radius: 1px;
-webkit-border-radius: 1px;
border-radius: 1px;
}
#muji .chatroom .chatroom_participants .participants_invite_box .participants_invite_list .invite_one .invite_one_remove:hover,
#muji .chatroom .chatroom_participants .participants_invite_box .participants_invite_list .invite_one .invite_one_remove:focus {
background-color: #8299ad;
}
#muji .chatroom .chatroom_participants .participants_invite_box .participants_invite_list .invite_one.invite_unsupported .invite_one_remove:hover,
#muji .chatroom .chatroom_participants .participants_invite_box .participants_invite_list .invite_one.invite_unsupported .invite_one_remove:focus {
background-color: #ad625f;
}
#muji .chatroom .chatroom_participants .participants_invite_box .participants_invite_list .invite_one .invite_one_remove:active {
background-color: #5b6e80;
}
#muji .chatroom .chatroom_participants .participants_invite_box .participants_invite_list .invite_one.invite_unsupported .invite_one_remove:active {
background-color: #804847;
}
#muji .chatroom .chatroom_participants .participants_invite_box form.participants_invite_form {
height: 32px;
margin-left: 8px;
position: relative;
}
html[dir="rtl"] #muji .chatroom .chatroom_participants .participants_invite_box form.participants_invite_form {
margin-left: auto;
margin-left: 0;
margin-right: 8px;
}
#muji .chatroom .chatroom_participants .participants_invite_box form.participants_invite_form .invite_validate {
display: none;
}
#muji .chatroom .chatroom_participants .participants_invite_box form.participants_invite_form .invite_validate .invite_go {
background-position: 0 -329px;
width: 14px;
height: 11px;
opacity: 0.6;
display: block;
position: absolute;
top: 11px;
right: 16px;
}
html[dir="rtl"] #muji .chatroom .chatroom_participants .participants_invite_box form.participants_invite_form .invite_validate .invite_go {
right: auto;
left: 8px;
}
#muji .chatroom .chatroom_participants .participants_invite_box form.participants_invite_form .invite_validate .invite_go:hover,
#muji .chatroom .chatroom_participants .participants_invite_box form.participants_invite_form .invite_validate .invite_go:active {
opacity: 1;
}
#muji .chatroom .chatroom_participants .participants_invite_box form.participants_invite_form .invite_validate .invite_separator,
#muji .chatroom form.chatroom_form .message_separator {
background: #e9e9e9;
width: 1px;
position: absolute;
top: 6px;
bottom: 6px;
}
#muji .chatroom .chatroom_participants .participants_invite_box form.participants_invite_form .invite_validate .invite_separator {
right: 40px;
}
html[dir="rtl"] #muji .chatroom .chatroom_participants .participants_invite_box form.participants_invite_form .invite_validate .invite_separator {
right: auto;
left: 32px;
}
#muji .chatroom .chatroom_participants .participants_invite_box form.participants_invite_form .invite_input_container {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 41px;
}
html[dir="rtl"] #muji .chatroom .chatroom_participants .participants_invite_box form.participants_invite_form .invite_input_container {
right: 0;
left: 41px;
}
#muji .chatroom .chatroom_participants .participants_invite_box form.participants_invite_form input.invite_xid {
font-size: 0.8em;
width: 100%;
height: 100%;
}
#muji .chatroom .chatroom_participants .participants_invite_box .participants_invite_search {
max-height: 220px;
overflow: auto;
}
#muji .chatroom .chatroom_participants .participants_invite_box .participants_invite_search .participant_search_one {
border-top: 1px solid #e1e1e1;
height: 28px;
display: block;
position: relative;
}
#muji .chatroom .chatroom_participants .participants_invite_box .participants_invite_search .participant_search_one.hover,
#muji .chatroom .chatroom_participants .participants_invite_box .participants_invite_search .participant_search_one.focus {
background: #f5f7ff;
}
#muji .chatroom .chatroom_participants .participants_invite_box .participants_invite_search .participant_search_one.active {
background: #eef1f8;
}
#muji .chatroom .chatroom_participants .participants_invite_box .participants_invite_search .participant_search_one.participant_search_unsupported {
background: #f6f6f6;
color: #969696;
}
#muji .chatroom .chatroom_participants .participants_invite_box .participants_invite_search .participant_search_one.participant_search_unsupported.hover,
#muji .chatroom .chatroom_participants .participants_invite_box .participants_invite_search .participant_search_one.participant_search_unsupported.focus {
background: #f1f1f1;
}
#muji .chatroom .chatroom_participants .participants_invite_box .participants_invite_search .participant_search_one.participant_search_unsupported.active {
background: #efefef;
}
#muji .chatroom .chatroom_participants .participants_invite_box .participants_invite_search .participant_search_one .avatar-container {
text-align: center;
height: 20px;
width: 20px;
margin: 4px 0 0 6px;
float: left;
}
html[dir="rtl"] #muji .chatroom .chatroom_participants .participants_invite_box .participants_invite_search .participant_search_one .avatar-container {
float: right;
}
#muji .chatroom .chatroom_participants .participants_invite_box .participants_invite_search .participant_search_one .avatar-container .avatar {
max-height: 20px;
max-width: 20px;
}
#muji .chatroom .chatroom_participants .participants_invite_box .participants_invite_search .participant_search_one .details {
position: absolute;
top: 0;
left: 40px;
right: 0;
bottom: 0;
}
html[dir="rtl"] #muji .chatroom .chatroom_participants .participants_invite_box .participants_invite_search .participant_search_one .details {
right: 40px;
left: 0;
}
#muji .chatroom .chatroom_participants .participants_invite_box .participants_invite_search .participant_search_one .details .name,
#muji .chatroom .chatroom_participants .participants_invite_box .participants_invite_search .participant_search_one .details .feature {
position: absolute;
display: block;
}
#muji .chatroom .chatroom_participants .participants_invite_box .participants_invite_search .participant_search_one .details .name {
font-size: 0.8em;
top: 6px;
left: 0;
right: 50px;
bottom: 0;
}
html[dir="rtl"] #muji .chatroom .chatroom_participants .participants_invite_box .participants_invite_search .participant_search_one .details .name {
right: 0;
left: 50px;
}
#muji .chatroom .chatroom_participants .participants_invite_box .participants_invite_search .participant_search_one .details .feature {
width: 16px;
height: 16px;
top: 6px;
right: 16px;
opacity: 0.75;
display: none;
}
html[dir="rtl"] #muji .chatroom .chatroom_participants .participants_invite_box .participants_invite_search .participant_search_one .details .feature {
right: auto;
left: 7px;
}
#muji .chatroom .chatroom_participants .participants_invite_box .participants_invite_search .participant_search_one.participant_search_has_audio .details .feature,
#muji .chatroom .chatroom_participants .participants_invite_box .participants_invite_search .participant_search_one.participant_search_has_video .details .feature {
display: block;
}
#muji .chatroom .chatroom_participants .participants_invite_box .participants_invite_search .participant_search_one.participant_search_has_audio .details .feature {
background-position: 0 -340px;
}
#muji .chatroom .chatroom_participants .participants_invite_box .participants_invite_search .participant_search_one.participant_search_has_video .details .feature {
background-position: 0 -356px;
}
#muji .chatroom .chatroom_view {
padding: 4px 4px 12px 8px;
overflow: auto;
position: absolute;
top: 41px;
left: 0;
right: 0;
bottom: 41px;
}
html[dir="rtl"] #muji .chatroom .chatroom_view {
padding-left: 8px;
}
#muji .chatroom .chatroom_view .room_message {
margin-top: 10px;
position: relative;
}
#muji .chatroom .chatroom_view .room_message.me .message_content {
float: left;
}
html[dir="rtl"] #muji .chatroom .chatroom_view .room_message.me .message_content {
float: right;
}
#muji .chatroom .chatroom_view .room_message.him .message_content {
margin-right: 30px;
float: right;
}
html[dir="rtl"] #muji .chatroom .chatroom_view .room_message.him .message_content {
margin-right: auto;
margin-left: 30px;
float: left;
}
#muji .chatroom .chatroom_view .room_message .message_content .message_bubble {
font-size: 0.85em;
padding: 7px 12px 8px 12px;
display: block;
-moz-border-radius: 6px;
-webkit-border-radius: 6px;
border-radius: 6px;
}
#muji .chatroom .chatroom_view .room_message.me .message_content .message_bubble {
background-color: #8dc2ef;
-moz-border-radius-bottomleft: 0;
-webkit-border-bottom-left-radius: 0;
border-bottom-left-radius: 0;
}
html[dir="rtl"] #muji .chatroom .chatroom_view .room_message.me .message_content .message_bubble {
-moz-border-radius-bottomleft: 6px;
-webkit-border-bottom-left-radius: 6px;
border-bottom-left-radius: 6px;
-moz-border-radius-bottomright: 0;
-webkit-border-bottom-right-radius: 0;
border-bottom-right-radius: 0;
}
#muji .chatroom .chatroom_view .room_message.him .message_content .message_bubble {
background-color: #bcdf6a;
-moz-border-radius-bottomright: 0;
-webkit-border-bottom-right-radius: 0;
border-bottom-right-radius: 0;
}
html[dir="rtl"] #muji .chatroom .chatroom_view .room_message.him .message_content .message_bubble {
-moz-border-radius-bottomright: 6px;
-webkit-border-bottom-right-radius: 6px;
border-bottom-right-radius: 6px;
-moz-border-radius-bottomleft: 0;
-webkit-border-bottom-left-radius: 0;
border-bottom-left-radius: 0;
}
#muji .chatroom .chatroom_view .room_message .message_content .message_author {
color: #6c6c6c;
font-size: 0.75em;
margin-top: 2px;
display: block;
}
#muji .chatroom .chatroom_view .room_message.him .message_content .message_author {
text-align: right;
}
html[dir="rtl"] #muji .chatroom .chatroom_view .room_message.him .message_content .message_author {
text-align: left;
}
#muji .chatroom .chatroom_view .room_message .message_avatar {
position: absolute;
right: 0;
bottom: 16px;
}
html[dir="rtl"] #muji .chatroom .chatroom_view .room_message .message_avatar {
right: auto;
left: 0;
}
#muji .chatroom .chatroom_view .room_message .message_avatar.avatar-container {
text-align: center;
height: 24px;
width: 24px;
}
#muji .chatroom .chatroom_view .room_message .message_avatar.avatar-container .avatar {
max-height: 24px;
max-width: 24px;
}
#muji .chatroom form.chatroom_form {
background: #fcfcfc;
border-top: 1px solid #e1e1e1;
height: 40px;
position: absolute;
bottom: 0;
left: 0;
right: 0;
}
#muji .chatroom form.chatroom_form .message_icon {
background-position: 0 -272px;
width: 17px;
height: 15px;
position: absolute;
top: 13px;
left: 12px;
}
html[dir="rtl"] #muji .chatroom form.chatroom_form .message_icon {
left: auto;
right: 12px;
}
#muji .chatroom form.chatroom_form .message_separator {
left: 40px;
}
html[dir="rtl"] #muji .chatroom form.chatroom_form .message_separator {
left: auto;
right: 40px;
}
#muji .chatroom form.chatroom_form .message_input_container {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 52px;
}
html[dir="rtl"] #muji .chatroom form.chatroom_form .message_input_container {
left: auto;
right: 52px;
}
#muji .chatroom form.chatroom_form .message_input_container input.message_input {
font-size: 0.8em;
width: 100%;
height: 100%;
}

View file

@ -108,7 +108,8 @@ html[dir="rtl"] .general-wait-content {
.mam-hidable,
.commands-hidable,
.privacy-hidable,
.xmpplinks-hidable {
.xmpplinks-hidable,
.muji-hidable {
display: none;
}

View file

@ -327,6 +327,93 @@ html[dir="rtl"] #page-engine .list .user .user-details .avatar-container {
margin-bottom: 10px;
}
#page-engine .one-line {
position: relative;
}
#page-engine .one-line.is-sending {
opacity: 0.6;
}
#page-engine .one-line .correction-edit,
#page-engine .one-line .correction-label,
#page-engine .one-line.user-message[data-edited] .corrected-info,
#page-engine .one-line .message-marker {
font-size: 0.8em;
position: absolute;
right: 0;
top: 0;
}
html[dir="rtl"] #page-engine .one-line .correction-edit,
html[dir="rtl"] #page-engine .one-line .correction-label,
html[dir="rtl"] #page-engine .one-line.user-message[data-edited] .corrected-info,
html[dir="rtl"] #page-engine .one-line .message-marker {
left: 0;
right: auto;
}
#page-engine .one-line .correction-edit,
#page-engine .one-line .correction-label {
border: 1px solid #7f7f7f;
color: black;
font-size: 0.8em;
text-decoration: none;
margin-top: -1px;
padding: 2px 5px;
position: absolute;
right: 0;
top: 0;
}
#page-engine .one-line .correction-edit {
opacity: 0.4;
display: none;
}
#page-engine .page-engine-chan[data-correction="true"] .one-line .correction-edit:hover,
#page-engine .page-engine-chan[data-correction="true"] .one-line .correction-edit:focus {
opacity: 1;
}
#page-engine .one-line.user-message[data-edited] .corrected-info,
#page-engine .one-line .message-marker {
color: #969696;
margin-top: 2px;
}
#page-engine .one-line .message-marker {
display: none;
}
#page-engine .one-line .message-marker.message-marker-read {
background-position: 0 -2227px;
padding-left: 11px;
}
#page-engine .page-engine-chan[data-correction="true"] .one-line.user-message[data-mode="me"]:last-child:hover .correction-edit {
display: block;
}
#page-engine .one-line.correction-active .corrected-info,
#page-engine .one-line.user-message[data-mode="me"]:last-child:hover .corrected-info {
display: none;
}
#page-engine .one-line.correction-active .message-marker,
#page-engine .one-line.user-message[data-mode="me"]:last-child:hover .message-marker {
display: none !important;
}
#page-engine .one-line .message-content {
margin-right: 80px;
}
html[dir="rtl"] #page-engine .one-line .message-content {
margin-right: 0;
margin-left: 80px;
}
#page-engine .one-line,
#page-engine .one-group b.name {
padding-left: 50px;
@ -339,6 +426,10 @@ html[dir="rtl"] #page-engine .one-group b.name {
padding-right: 50px;
}
#page-engine .one-line.correction-active {
opacity: 0.5;
}
#page-engine .one-group b.name {
display: block;
margin-bottom: 4px;
@ -556,7 +647,9 @@ html[dir="rtl"] #page-engine .text .chat-tools-smileys {
}
body.in_jingle_call #page-engine .text .tools-jingle-video,
body.in_jingle_call #page-engine .text .tools-jingle-audio {
body.in_jingle_call #page-engine .text .tools-jingle-audio,
body.in_muji_call #page-engine .text .tools-jingle-video,
body.in_muji_call #page-engine .text .tools-jingle-audio {
opacity: 0.35;
cursor: default;
}
@ -834,22 +927,67 @@ body.in_jingle_call #page-engine .text .tools-jingle-audio {
}
#page-engine .text .compose,
#page-engine .muc-ask {
#page-engine .muc-ask,
#page-engine .correction-toolbox {
position: absolute;
left: 0;
}
#page-engine .text .compose {
#page-engine .text .compose,
#page-engine .correction-toolbox {
top: 29px;
right: 12px;
bottom: 12px;
}
#page-engine .text .compose {
right: 12px;
}
html[dir="rtl"] #page-engine .text .compose {
right: 0;
left: 12px;
}
#page-engine .text.correction-active .compose {
left: 120px;
}
html[dir="rtl"] #page-engine .text.correction-active .compose {
right: 120px;
}
#page-engine .correction-toolbox {
width: 120px;
}
html[dir="rtl"] #page-engine .correction-toolbox {
right: 0;
left: auto;
}
#page-engine .correction-toolbox .correction-editing,
#page-engine .correction-toolbox .correction-cancel {
display: block;
color: black;
font-size: 0.8em;
text-decoration: none;
text-align: center;
margin: 7px 12px;
padding: 2px 5px;
}
#page-engine .correction-toolbox .correction-editing {
font-weight: bold;
margin-top: 8px;
}
#page-engine .correction-toolbox .correction-cancel {
background: #d15e6b;
border: 1px solid #cc273f;
color: white;
text-shadow: 0 1px 1px rgba(0,0,0,0.5);
}
#page-engine .muc-ask {
right: 0;
bottom: 0;
@ -872,6 +1010,21 @@ html[dir="rtl"] #page-engine .text .compose {
border-top-left-radius: 0;
}
#page-engine .text.correction-active textarea {
-moz-border-radius-bottomleft: 0;
-webkit-border-bottom-left-radius: 0;
border-bottom-left-radius: 0;
}
html[dir="rtl"] #page-engine .text.correction-active textarea {
-moz-border-radius-bottomleft: 3px;
-webkit-border-bottom-left-radius: 3px;
border-bottom-left-radius: 3px;
-moz-border-radius-bottomright: 0;
-webkit-border-bottom-right-radius: 0;
border-bottom-right-radius: 0;
}
#page-engine .muc-ask {
background-color: #e8f1f3;
height: 64px;

View file

@ -356,7 +356,10 @@ html[dir="rtl"] .manage-infos p.bm-group input {
background-position: 1px -2047px;
}
body.in_jingle_call .call-jingle {
body.in_jingle_call .call-jingle,
body.in_muji_call .call-jingle,
body.in_jingle_call .roster-muji,
body.in_muji_call .roster-muji {
opacity: 0.35;
}
@ -367,7 +370,10 @@ body.in_jingle_call .call-jingle {
display: none;
}
body.in_jingle_call .call-jingle a {
body.in_jingle_call .call-jingle a,
body.in_muji_call .call-jingle a,
body.in_jingle_call .roster-muji a,
body.in_muji_call .roster-muji a {
cursor: default;
}
@ -455,7 +461,7 @@ html[dir="rtl"] #roster .roster-icon {
width: 16px;
display: block;
}
#roster .add,
#page-engine .text .tools-add {
background-position: 0 -1047px;
@ -469,7 +475,11 @@ html[dir="rtl"] #roster .roster-icon {
#page-switch .groupchat-default {
background-position: 0 -1082px;
}
#roster .muji {
background-position: 0 -2047px;
}
#roster .more {
background-position: 0 -1100px;
}
@ -520,7 +530,15 @@ html[dir="rtl"] .buddy-conf-subarrow {
margin-right: 9px;
float: right;
}
.buddy-conf-muji .buddy-conf-subarrow {
margin-left: 8px;
}
html[dir="rtl"] .buddy-conf-muji .buddy-conf-subarrow {
margin-right: 8px;
}
.buddy-conf-subitem {
background-color: rgb(0,0,0);
background-color: rgba(0,0,0,0.8);

View file

@ -61,46 +61,51 @@ html[dir="rtl"] #top-content .tools-all {
float: left;
}
#top-content .jingle {
#top-content .call {
background-position: 7px -2114px;
display: none;
}
#top-content .jingle.video {
#top-content .call .notify {
margin-left: 0;
left: -2px;
}
#top-content .call.video {
background-position: 7px -2205px;
}
#top-content .jingle.active,
#top-content .jingle.streaming {
#top-content .call.active,
#top-content .call.streaming {
display: block;
}
#top-content .jingle.active {
#top-content .call.active {
-webkit-animation: tool_active 1.5s infinite ease-in-out;
-moz-animation: tool_active 1.5s infinite ease-in-out;
-o-animation: tool_active 1.5s infinite ease-in-out;
animation: tool_active 1.5s infinite ease-in-out;
}
#top-content .jingle.streaming {
#top-content .call.streaming {
padding-left: 30px;
}
#top-content .jingle .streaming-items {
#top-content .call .streaming-items {
display: none;
}
#top-content .jingle.streaming .streaming-items {
#top-content .call.streaming .streaming-items {
display: block;
}
#top-content .jingle.streaming .streaming-items .counter {
#top-content .call.streaming .streaming-items .counter {
font-size: 11px;
font-style: italic;
font-weight: bold;
}
#top-content .jingle.streaming .streaming-items a.stop {
#top-content .call.streaming .streaming-items a.stop {
background: #cc283f;
border-left: 1px solid #a12032;
color: #ffffff;
@ -116,7 +121,7 @@ html[dir="rtl"] #top-content .tools-all {
border-bottom-right-radius: 4px;
}
#top-content .jingle.streaming .streaming-items a.stop:active {
#top-content .call.streaming .streaming-items a.stop:active {
background: #a92134;
padding-top: 6px;
padding-bottom: 6px;
@ -135,23 +140,27 @@ html[dir="rtl"] #top-content .tools-all {
#top-content .notifications:hover,
#top-content .music:hover,
#top-content .jingle.streaming.video:hover {
#top-content .call.streaming.video:hover,
.in_muji_call #top-content .call.streaming.audio:hover {
cursor: pointer;
}
#top-content .music:hover,
#top-content .notifications:hover,
#top-content .jingle.streaming.video:hover,
#top-content .call.streaming.video:hover,
.in_muji_call #top-content .call.streaming.audio:hover,
#top-content .music:focus,
#top-content .notifications:focus,
#top-content .jingle.streaming.video:focus {
#top-content .call.streaming.video:focus,
.in_muji_call #top-content .call.streaming.audio:focus {
background-color: rgb(232,241,243);
background-color: rgba(232,241,243,0.7);
}
#top-content .music:active,
#top-content .notifications:active,
#top-content .jingle.streaming.video:active {
#top-content .call.streaming.video:active,
.in_muji_call #top-content .call.streaming.audio:active {
background-color: rgb(232,241,243);
background-color: rgba(232,241,243,0.8);
}
@ -485,25 +494,25 @@ html[dir="rtl"] .music-content .list {
height: 15px;
}
.jingle-content {
.call-content {
text-shadow: none;
width: 230px;
right: -102px;
}
html[dir="rtl"] .jingle-content {
html[dir="rtl"] .call-content {
left: -102px;
}
.jingle-content .tools-content-subitem {
.call-content .tools-content-subitem {
position: relative;
}
.jingle-content .jingle-notify {
.call-content .call-notify {
height: 90px;
}
.jingle-content .jingle-notify .avatar-pane {
.call-content .call-notify .avatar-pane {
width: 100px;
position: absolute;
left: 0;
@ -517,12 +526,12 @@ html[dir="rtl"] .jingle-content {
border-top-left-radius: 4px;
}
html[dir="rtl"] .jingle-content .jingle-notify .avatar-pane {
html[dir="rtl"] .call-content .call-notify .avatar-pane {
left: auto;
right: 0;
}
.jingle-content .jingle-notify .avatar-pane .avatar-container {
.call-content .call-notify .avatar-pane .avatar-container {
overflow: hidden;
position: absolute;
left: 0;
@ -531,7 +540,7 @@ html[dir="rtl"] .jingle-content .jingle-notify .avatar-pane {
top: 0;
}
.jingle-content .jingle-notify .avatar-pane .avatar-container .avatar {
.call-content .call-notify .avatar-pane .avatar-container .avatar {
min-height: 100%;
max-height: 100%;
min-width: 100%;
@ -543,7 +552,7 @@ html[dir="rtl"] .jingle-content .jingle-notify .avatar-pane {
border-bottom-left-radius: 5px;
}
html[dir="rtl"] .jingle-content .jingle-notify .avatar-pane .avatar-container .avatar {
html[dir="rtl"] .call-content .call-notify .avatar-pane .avatar-container .avatar {
-moz-border-radius: 0;
-webkit-border-radius: 0;
border-radius: 0;
@ -555,45 +564,45 @@ html[dir="rtl"] .jingle-content .jingle-notify .avatar-pane .avatar-container .a
border-bottom-right-radius: 5px;
}
.jingle-content .jingle-notify .avatar-pane .icon {
.call-content .call-notify .avatar-pane .icon {
opacity: 0.75;
position: absolute;
left: 8px;
bottom: 8px;
}
.jingle-content .jingle-notify.notify-call_audio .avatar-pane .icon {
.call-content .call-notify.notify-call_audio .avatar-pane .icon {
background-position: 0 -120px;
width: 33px;
height: 33px;
}
.jingle-content .jingle-notify.notify-call_video .avatar-pane .icon {
.call-content .call-notify.notify-call_video .avatar-pane .icon {
background-position: 0 -154px;
width: 33px;
height: 22px;
}
.jingle-content .jingle-notify.notify-connecting .avatar-pane .icon {
.call-content .call-notify.notify-connecting .avatar-pane .icon {
background-position: 0 -175px;
width: 33px;
height: 32px;
}
.jingle-content .jingle-notify.notify-error .avatar-pane .icon {
.call-content .call-notify.notify-error .avatar-pane .icon {
background-position: 0 -207px;
width: 33px;
height: 31px;
}
.jingle-content .jingle-notify.notify-local_ended .avatar-pane .icon,
.jingle-content .jingle-notify.notify-remote_ended .avatar-pane .icon {
.call-content .call-notify.notify-local_ended .avatar-pane .icon,
.call-content .call-notify.notify-remote_ended .avatar-pane .icon {
background-position: 0 -238px;
width: 33px;
height: 34px;
}
.jingle-content .jingle-notify .notification-content {
.call-content .call-notify .notification-content {
color: #ffffff;
text-align: left;
text-shadow: 0 1px 1px rgb(0,0,0);
@ -606,28 +615,28 @@ html[dir="rtl"] .jingle-content .jingle-notify .avatar-pane .avatar-container .a
left: 100px;
}
html[dir="rtl"] .jingle-content .jingle-notify .notification-content {
html[dir="rtl"] .call-content .call-notify .notification-content {
text-align: right;
right: 100px;
left: 0;
}
.jingle-content .jingle-notify .notification-content .fullname,
.jingle-content .jingle-notify .notification-content .text {
.call-content .call-notify .notification-content .fullname,
.call-content .call-notify .notification-content .text {
display: block;
}
.jingle-content .jingle-notify .notification-content .fullname {
.call-content .call-notify .notification-content .fullname {
font-weight: bold;
}
.jingle-content .jingle-notify .notification-content .text {
.call-content .call-notify .notification-content .text {
font-size: 12px;
text-transform: lowercase;
margin-top: 2px;
}
.jingle-content .jingle-notify .notification-content .reply-buttons {
.call-content .call-notify .notification-content .reply-buttons {
text-align: center;
padding-left: 10px;
position: absolute;
@ -636,31 +645,31 @@ html[dir="rtl"] .jingle-content .jingle-notify .notification-content {
bottom: 20px;
}
html[dir="rtl"] .jingle-content .jingle-notify .notification-content .reply-buttons {
html[dir="rtl"] .call-content .call-notify .notification-content .reply-buttons {
padding-left: 0;
padding-right: 10px;
}
.jingle-content .jingle-notify .notification-content .reply-buttons a.reply-button {
.call-content .call-notify .notification-content .reply-buttons a.reply-button {
margin-left: 4px;
float: left;
}
html[dir="rtl"] .jingle-content .jingle-notify .notification-content .reply-buttons a.reply-button {
html[dir="rtl"] .call-content .call-notify .notification-content .reply-buttons a.reply-button {
margin-left: 0;
margin-right: 4px;
float: right;
}
.jingle-content .jingle-notify .notification-content .reply-buttons a.reply-button:active {
.call-content .call-notify .notification-content .reply-buttons a.reply-button:active {
margin-top: 0;
}
.jingle-content .jingle-notify .notification-content .reply-buttons a.reply-button.first {
.call-content .call-notify .notification-content .reply-buttons a.reply-button.first {
margin-left: 0;
}
html[dir="rtl"] .jingle-content .jingle-notify .notification-content .reply-buttons a.reply-button.first {
html[dir="rtl"] .call-content .call-notify .notification-content .reply-buttons a.reply-button.first {
margin-right: 0;
}

Some files were not shown because too many files have changed in this diff Show more